home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / trn / part06 < prev    next >
Encoding:
Internet Message Format  |  1991-12-02  |  83.4 KB

  1. Subject:  v25i009:  trn 2.0 - threaded newsreader based on rn 4.4, Part06/13
  2. Newsgroups: comp.sources.unix
  3. Approved: vixie@pa.dec.com
  4.  
  5. Submitted-by: davison@borland.com (Wayne Davison)
  6. Posting-number: Volume 25, Issue 9
  7. Archive-name: trn/part06
  8.  
  9. #! /bin/sh
  10. # This is a shell archive.  Remove anything before this line, then unpack
  11. # it by saving it into a file and typing "sh file".  To overwrite existing
  12. # files, type "sh file -c".  You can also feed this as standard input via
  13. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  14. # will see the following message at the end:
  15. #        "End of archive 6 (of 13)."
  16. # Contents:  Pnews.SH help.c mt-read.c rn.c util.c
  17. # Wrapped by vixie@cognition.pa.dec.com on Tue Dec  3 16:34:53 1991
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. if test -f 'Pnews.SH' -a "${1}" != "-c" ; then 
  20.   echo shar: Will not clobber existing file \"'Pnews.SH'\"
  21. else
  22. echo shar: Extracting \"'Pnews.SH'\" \(17117 characters\)
  23. sed "s/^X//" >'Pnews.SH' <<'END_OF_FILE'
  24. case $CONFIG in
  25. X    '') . ./config.sh ;;
  26. esac
  27. echo "Extracting Pnews (with variable substitutions)"
  28. X$spitshell >Pnews <<!GROK!THIS!
  29. X$startsh
  30. X# $Id: Pnews.SH,v 4.4.2.1 1991/12/01 18:05:42 sob PATCH_2 sob $
  31. X#
  32. X# $Log: Pnews.SH,v $
  33. X# Revision 4.4.2.1  1991/12/01  18:05:42  sob
  34. X# Patchlevel 2
  35. X#
  36. X# Revision 4.4  1991/09/09  20:18:23  sob
  37. X# release 4.4
  38. X#
  39. X#
  40. X# 
  41. X# This software is Copyright 1991 by Stan Barber. 
  42. X#
  43. X# Permission is hereby granted to copy, reproduce, redistribute or otherwise
  44. X# use this software as long as: there is no monetary profit gained
  45. X# specifically from the use or reproduction of this software, it is not
  46. X# sold, rented, traded or otherwise marketed, and this copyright notice is
  47. X# included prominently in any copy made. 
  48. X#
  49. X# The author make no claims as to the fitness or correctness of this software
  50. X# for any use whatsoever, and it is provided as is. Any use of this software
  51. X# is at the user's own risk. 
  52. X#
  53. X# syntax: Pnews -h headerfile            or
  54. X#      Pnews -h headerfile oldarticle    or
  55. X#         Pnews newsgroup title            or just
  56. X#         Pnews
  57. X
  58. export PATH || (echo "OOPS, this isn't sh.  Desperation time.  I will feed myself to sh."; sh \$0; kill \$\$)
  59. X
  60. X# System dependencies
  61. X
  62. mailer="${mailer-/bin/mail}"
  63. X# if you change this to something that does signatures, take out signature code
  64. X
  65. case $portable in
  66. define)
  67. X# your site name
  68. case "$hostcmd" in
  69. X'') sitename="$sitename" ;;
  70. X*)  sitename=\`$hostcmd\` ;;
  71. esac
  72. case \$sitename in
  73. X    *.*)
  74. X        ;;
  75. X    *)
  76. X        sitename=\${sitename}.$domain
  77. X        ;;
  78. esac
  79. X# where recordings, distributions and moderators are kept
  80. lib=\`$filexp $lib\`
  81. X# where important rn things are kept
  82. rnlib=\`$filexp $rnlib\`
  83. X;;
  84. undef)
  85. X# your site name
  86. sitename="$sitename"
  87. X# where recordings, distributions and moderators are kept
  88. lib="$lib"
  89. X# where important rn things are kept
  90. rnlib="$rnlib"
  91. X;;
  92. esac
  93. X
  94. X# your organization name
  95. orgname="$orgname"
  96. X# what pager you use--if you have kernal paging use cat
  97. pager="\${PAGER-$pager}"
  98. X# how you derive full names, bsd, usg, or other
  99. nametype="$nametype"
  100. X# default editor
  101. defeditor="$defeditor"
  102. X# how not to echo with newline
  103. n="$n"
  104. c="$c"
  105. X
  106. X# You should also look at the distribution warnings below marked !DIST!
  107. X# to make sure any distribution regions you are a member of are included.
  108. X# The following are some prototypical distribution groups.  If you do not
  109. X# use them all set the unused ones to a non-null string such as 'none'.
  110. loc="$locpref"
  111. org="$orgpref"
  112. city="$citypref"
  113. state="$statepref"
  114. cntry="$cntrypref"
  115. cont="$contpref"
  116. X
  117. test=${test-test}
  118. sed=${sed-sed}
  119. echo=${echo-echo}
  120. cat=${cat-cat}
  121. egrep=${egrep-egrep}
  122. grep=${grep-grep}
  123. rm=${rm-rm}
  124. tr=${tr-tr}
  125. inews=${inews-inews}
  126. nidump=${nidump}
  127. ypmatch=${ypmatch}
  128. X
  129. X!GROK!THIS!
  130. case "$ignoreorg" in
  131. define) $spitshell >>Pnews <<'!NO!SUBS!'
  132. orgname=${NEWSORG-$orgname}
  133. X!NO!SUBS!
  134. X    ;;
  135. X*)    $spitshell >>Pnews <<'!NO!SUBS!'
  136. orgname=${NEWSORG-${ORGANIZATION-$orgname}}
  137. X!NO!SUBS!
  138. X    ;;
  139. esac
  140. X$spitshell >>Pnews <<'!NO!SUBS!'
  141. dotdir=${DOTDIR-${HOME-$LOGDIR}}
  142. tmpart=$dotdir/.article
  143. X
  144. if $test -f $dotdir/.pnewsexpert; then
  145. X    expertise=expert
  146. else
  147. X    $cat <<'EOM'
  148. I see you've never used this version of Pnews before.  I will give you extra
  149. help this first time through, but then you must remember what you learned.
  150. If you don't understand any question, type h and a CR (carriage return) for
  151. help.
  152. X
  153. If you've never posted an article to the net before, it is HIGHLY recommended
  154. that you read the netiquette document found in news.announce.newusers so
  155. that you'll know to avoid the commonest blunders.  To do that, interrupt
  156. Pnews, and get to the top-level prompt of rn.  Type "g news.announce.newusers"
  157. and you are on your way.
  158. X
  159. XEOM
  160. X    expertise=beginner
  161. fi
  162. X
  163. case $cntry in
  164. X  can) stpr=Province ;;
  165. X  *)   stpr=State ;;
  166. esac
  167. X
  168. headerfile=""
  169. case $# in
  170. X0) ;;
  171. X*)  case $1 in
  172. X    -h)
  173. X    headerfile="$2"
  174. X    shift
  175. X    shift
  176. X    case $# in
  177. X    0)
  178. X        oldart=""
  179. X        ;;
  180. X    *)
  181. X        oldart="$1"
  182. X        shift
  183. X        ;;
  184. X    esac
  185. X    ;;
  186. X    esac
  187. X    ;;
  188. esac
  189. X
  190. case $headerfile in
  191. X'')
  192. X    . $rnlib/Pnews.header
  193. X    ;;
  194. X*)
  195. X    $cat < $headerfile  > $tmpart
  196. X    ;;
  197. esac
  198. X    rescue="sleep 1; $cat $tmpart >>${HOME-$LOGDIR}/dead.article ; $echo Article appended to ${HOME-$LOGDIR}/dead.article ; exit"
  199. X    trap "$rescue" 1
  200. X    trap "$rescue" 2
  201. X
  202. X$echo ""
  203. X
  204. X# extract the newsgroups list and distribution
  205. hdr_newsgroups=`$sed -n -e '/^Newsgroups:/{' -e 's///' -e 's/,/ /g' -e p -e q -e '}' $tmpart`
  206. hdr_distribution=`$sed -n -e '/^Distribution:/{' -e 's///' -e p -e q -e '}' $tmpart`
  207. X
  208. X# check for "poster" magic cookie
  209. flag=0
  210. for ng in $hdr_newsgroups ; do
  211. X    case "$ng" in
  212. X    poster)    flag=1 ;;
  213. X    *)    ;;
  214. X    esac
  215. done
  216. case $flag in
  217. X1)
  218. X    $echo " "
  219. X    $echo "The original author has requested that messages be sent back via"
  220. X    $echo "mail rather than posting to news.  Do you want to jump out of this"
  221. X    $echo $n "and mail your reply instead? [yn] $c"
  222. X    read ans
  223. X    case $ans in
  224. X    n*) ;;
  225. X    *)  exit ;;
  226. X    esac
  227. X    $echo " "
  228. X    $echo "OK, but you will have to edit the 'Newsgroups:' line in the message."
  229. X    ;;
  230. esac
  231. X  
  232. X# play recorded message
  233. if $test -s ${lib}/recording ; then
  234. X     for ng in $hdr_newsgroups ; do
  235. X    _rec1=${lib}/`$sed -n "/^$ng/s/^.*    //p" ${lib}/recording`
  236. X    _tmp=`$echo $ng |$sed "s/\..*//"`
  237. X    _rec2=${lib}/`$cat -s ${lib}/recording|$grep ${_tmp}.all|$sed "s/^.*    //"`
  238. X    if $test -f ${_rec1} ; then
  239. X        $cat -s ${_rec1}
  240. X    fi
  241. X    if $test -f ${_rec2} ; then
  242. X        $cat -s ${_rec2}
  243. X    fi
  244. X    done
  245. fi
  246. X
  247. X# determine the distribution of this message
  248. set X $hdr_distribution
  249. shift
  250. if $test $# -gt 0 ; then
  251. X    dist=$1.whatever
  252. else
  253. X    set X $hdr_newsgroups
  254. X    shift
  255. X    if $test $# -gt 0 ; then
  256. X    dist=$1.whatever
  257. X    else
  258. X    dist=misc.whatever
  259. X    fi
  260. fi
  261. case $dist in
  262. X*.*)
  263. X    ;;
  264. X*)
  265. X    dist=$dist.whatever
  266. X    ;;
  267. esac
  268. X
  269. X# tell them what we think they are doing... !DIST!
  270. case $dist in
  271. world.*|comp.*|news.*|sci.*|rec.*|misc.*|soc.*|talk.*|alt.*)
  272. X    $cat <<'EOM'
  273. This program posts news to thousands of machines throughout the entire
  274. civilized world.  Your message will cost the net hundreds if not thousands of
  275. dollars to send everywhere.  Please be sure you know what you are doing.
  276. X
  277. XEOM
  278. X    ;;
  279. vmsnet.*)
  280. X    $echo 'This program posts news to many machines.'
  281. X    ;;
  282. bit.*)
  283. X    $echo 'This program posts news to many machines on BITNET.'
  284. X    ;;
  285. ddn.*)
  286. X    $echo 'This program posts news to many machines throughout the internet.'
  287. X    ;;
  288. X$cont.*)
  289. X    $echo 'This program posts news to many machines throughout the continent.'
  290. X    ;;
  291. X$cntry.*)
  292. X    $echo 'This program posts news to many machines throughout the country.'
  293. X    ;;
  294. X$state.*)
  295. X    $echo 'This program posts news to many machines throughout the state.'
  296. X    ;;
  297. X$city.*)
  298. X    $echo 'This program posts news to many machines throughout the city.'
  299. X    ;;
  300. X$org.*)
  301. X    $echo 'This program posts news to machines throughout the organization.'
  302. X    ;;
  303. X$loc.*)
  304. X    $echo 'This program posts news to machines throughout the local organization.'
  305. X    ;;
  306. X*.*)
  307. X    $echo 'This program may post news to many machines.'
  308. X    ;;
  309. to.*)
  310. X    $echo 'This program may post news to a particular machine.'
  311. X    ;;
  312. X*)
  313. X    $echo 'This program posts news to everyone on the machine.'
  314. X    ;;
  315. esac
  316. ans=""
  317. while $test "$ans" = "" ; do
  318. X    $echo $n "Are you absolutely sure that you want to do this? [ny] $c"
  319. X    read ans
  320. X    case $ans in
  321. X    y*) ;;
  322. X    f*) ;;
  323. X    h*) $cat <<'EOH'
  324. X
  325. Type n or CR to exit, y to post.
  326. X
  327. XEOH
  328. X    ans="" ;;
  329. X    *) exit ;;
  330. X    esac
  331. done
  332. X
  333. file=h
  334. while $test "$file" = h ; do
  335. X    $echo ""
  336. X    $echo $n "Prepared file to include [none]: $c"
  337. X    read file
  338. X    case $file in
  339. X    h)
  340. X    $cat <<'EOH'
  341. X
  342. If you have already produced the body of your article, type the filename
  343. for it here.  If you just want to proceed directly to the editor, type a
  344. RETURN.  In any event, you will be allowed to edit as many times as you
  345. want before you send off the article.
  346. XEOH
  347. X    ;;
  348. X    '')
  349. X    $echo "" >> $tmpart
  350. X    state=edit
  351. X    ;;
  352. X    *)
  353. X    $cat $file >>$tmpart
  354. X    state=ask
  355. X    ;;
  356. X    esac
  357. done
  358. X
  359. X$echo ""
  360. X
  361. while true ; do
  362. X    case $state in
  363. X    edit)
  364. X    case $expertise in
  365. X    beginner)
  366. X        $cat </dev/null >$dotdir/.pnewsexpert
  367. X        $cat <<'EOMessage'
  368. A temporary file has been created for you to edit.  Be sure to leave at
  369. least one blank line between the header and the body of your message.
  370. X(And until a certain bug is fixed all over the net, don't start the body of
  371. your message with any indentation, or it may get eaten.)
  372. X
  373. Within the header may be fields that you don't understand.  If you don't
  374. understand a field (or even if you do), you can simply leave it blank, and
  375. it will go away when the article is posted.
  376. X
  377. Type return to get the default editor, or type the name of your favorite
  378. editor.
  379. X
  380. XEOMessage
  381. X        ;;
  382. X    esac
  383. X    case "${VISUAL-${EDITOR-}}" in
  384. X    '')
  385. X        tmp=h
  386. X        ;;
  387. X    *)
  388. X        tmp=''
  389. X        ;;
  390. X    esac
  391. X    while $test "$tmp" = h ; do
  392. X        $echo $n "Editor [${VISUAL-${EDITOR-$defeditor}}]: $c"
  393. X        read tmp
  394. X        case $tmp in
  395. X        h)
  396. X        $cat <<'EOH'
  397. X
  398. Type a return to get the default editor, or type the name of the editor you
  399. prefer.  The default editor depends on the VISUAL and EDITOR environment
  400. variables.
  401. X
  402. XEOH
  403. X        ;;
  404. X        '')
  405. X        ;;
  406. X        *)
  407. X        VISUAL=$tmp
  408. X        export VISUAL
  409. X        ;;
  410. X        esac
  411. X    done
  412. X    trap : 2
  413. X    ${VISUAL-${EDITOR-$defeditor}} $tmpart $oldart
  414. X    trap "$rescue" 2
  415. X    state=ask
  416. X    ;;
  417. X    
  418. X    ask)
  419. X    $echo ""
  420. X    $echo $n "Send, abort, edit, or list? $c"
  421. X    read ans
  422. X    
  423. X    case "$ans" in
  424. X    a*)
  425. X        state=rescue
  426. X        ;;
  427. X    e*)
  428. X        set $ans
  429. X        case $# in
  430. X        2)  VISUAL="$2" ;;
  431. X        esac
  432. X        state=edit
  433. X        ;;
  434. X    l*)
  435. X        $pager $tmpart
  436. X        state=ask
  437. X        ;;
  438. X    s*)
  439. X        state=send
  440. X        ;;
  441. X    h*)
  442. X        $cat <<'EOH'
  443. X
  444. Type s to send the article, a to abort and append the article to dead.article,
  445. e to edit the article again, or l to list the article.
  446. X
  447. To invoke an alternate editor, type 'e editor'.
  448. XEOH
  449. X    esac
  450. X    ;;
  451. X    
  452. X    send)
  453. X    set X `$sed < $tmpart -n -e '/^Newsgroups: /{' -e p -e q -e '}'`
  454. X    shift
  455. X    case $# in
  456. X    2)
  457. X        state=cleanup
  458. X        if $test -f $lib/moderators; then
  459. X        tryinews=no
  460. X        shift
  461. X        case "$1" in
  462. X        *,*) set `$echo $1 | tr ',' ' '`;;
  463. X        esac
  464. X        for newsgroup in $*; do
  465. X# the following screwy sed should prevent Eunice from hanging on no match
  466. X            moderator=`$sed <$lib/moderators \
  467. X            -e "/^$newsgroup[     ]/!s/.*//" \
  468. X            -e "s/^$newsgroup[     ]//"`
  469. X            case ${moderator}X in
  470. X            X)  tryinews=yes
  471. X            ;;
  472. X            *)
  473. X            $echo Mailing to moderator $moderator
  474. X            case "$sign" in
  475. X            n*) ;;
  476. X            *)
  477. X                if $test -f $dotdir/.signature; then
  478. X                $echo $n "Append .signature file? [y] $c"
  479. X                read ans
  480. X                case $ans in
  481. X                ''|y*)
  482. X                    $echo "-- " >> $tmpart
  483. X                    $cat $dotdir/.signature >> $tmpart
  484. X                    ;;
  485. X                esac
  486. X                fi
  487. X                sign=no
  488. X                ;;
  489. X            esac
  490. X            case "$mailer" in
  491. X            *recmail)
  492. X                $echo To: $moderator | $cat - $tmpart | $mailer
  493. X                ;;
  494. X            *)
  495. X                $mailer $moderator < $tmpart
  496. X                ;;
  497. X            esac
  498. X            case $? in
  499. X            0) ;;
  500. X            *)
  501. X                $echo Unable to mail to moderator $moderator
  502. X                state=rescue
  503. X                ;;
  504. X            esac
  505. X            ;;
  506. X            esac
  507. X        done
  508. X        else
  509. X        tryinews=yes
  510. X        fi
  511. X        case "$tryinews" in
  512. X        yes)
  513. X        if $sed '1,/^[     ]*$/{/^[A-Z][-A-Za-z0-9]*:[     ]*$/d;}' $tmpart |
  514. X            $inews -h ; then
  515. X            : null
  516. X        else
  517. X            state=rescue
  518. X        fi
  519. X        ;;
  520. X        esac
  521. X        ;;
  522. X    *)
  523. X        $echo ""
  524. X        $echo "Malformed Newsgroups line."
  525. X        $echo ""
  526. X        sleep 1
  527. X        state=edit
  528. X        ;;
  529. X    esac
  530. X    ;;
  531. X    rescue)
  532. X    if $test -s $tmpart; then
  533. X        $cat $tmpart >> ${HOME-$LOGDIR}/dead.article
  534. X        $echo "Article appended to ${HOME-$LOGDIR}/dead.article"
  535. X        $echo "A copy may be temporarily found in $tmpart"
  536. X    else
  537. X        $echo "Null article discarded."
  538. X    fi
  539. X    exit
  540. X    ;;
  541. X    cleanup)
  542. X    case "${AUTHORCOPY-none}" in
  543. X    none)
  544. X        ;;
  545. X    *)
  546. X        set X ${USER-${LOGNAME-`who am i`}} unknown
  547. X        shift
  548. X        $rnlib/mbox.saver $tmpart "." "." 0 0 Pnews $AUTHORCOPY "From $1 `date`"
  549. X        if $test $? -eq 0 ; then
  550. X        $echo "Article appended to $AUTHORCOPY"
  551. X        else
  552. X        $echo "Cannot append to $AUTHORCOPY"
  553. X        fi
  554. X        ;;
  555. X    esac
  556. X    exit
  557. X    ;;
  558. X    esac
  559. done
  560. X!NO!SUBS!
  561. X$eunicefix Pnews
  562. chmod 755 Pnews
  563. X$spitshell >Pnews.header <<'!NO!SUBS!'
  564. case $# in
  565. X0)
  566. X    ng=h
  567. X    while $test "$ng" = h ; do
  568. X    $echo ""
  569. X    $echo $n "Newsgroup(s): $c"
  570. X    read ng
  571. X    case $ng in
  572. X    h)
  573. X        $cat <<'EOH'
  574. X
  575. Type the name of one or more newsgroups to which you wish to post an article.
  576. If you want to post to multiple newsgroups, it is better to do them all at
  577. once than to post to each newsgroup individually, which defeats the news
  578. reading programs' strategies of eliminating duplicates.
  579. X
  580. Separate multiple newsgroup names with commas.
  581. XEOH
  582. X        ;;
  583. X    esac
  584. X    done
  585. X    ;;
  586. X*)
  587. X    ng=$1
  588. X    shift
  589. X    ;;
  590. esac
  591. case $ng in
  592. X*\ *)
  593. X    ng=`$echo "$ng" | $sed 's/[, ] */,/g'`
  594. X    ;;
  595. esac
  596. case $ng in
  597. bit.*|pubnet.*|bionet.*|vmsnet.*|comp.*|news.*|sci.*|rec.*|misc.*|soc.*|talk.*|alt.*)
  598. X    defdist=world
  599. X    dist=h
  600. X    ;;
  601. ddn.*)
  602. X    defdist=inet
  603. X    dist=h
  604. X    ;;
  605. to.*)
  606. X    defdist=''
  607. X    dist=''
  608. X    ;;
  609. X*.*)
  610. X    defdist=`expr "X$ng" : 'X\([a-z0-9]*\)'`
  611. X    dist=h
  612. X    ;;
  613. X*)
  614. X    defdist=''
  615. X    dist=''
  616. X    ;;
  617. esac
  618. X
  619. while $test "$dist" = h ; do
  620. X    if $test -f $lib/distributions; then
  621. X    $echo " "
  622. X    $echo "Your local distribution prefixes are:"
  623. X    $cat $lib/distributions
  624. X    $echo " "
  625. X    else
  626. X    $egrep -v '[     ]none$' <<EOM
  627. X
  628. Your local distribution prefixes are:
  629. X    Local organization:    $loc
  630. X    Organization:    $org
  631. X    City:        $city
  632. X    $stpr:          $state
  633. X    Country:        $cntry
  634. X    Continent:        $cont
  635. X    Everywhere:        world
  636. X
  637. XEOM
  638. X    fi
  639. X    $echo $n "Distribution ($defdist): $c"
  640. X    read dist
  641. X    case $dist in
  642. X    '') dist=$defdist ;;
  643. X    esac
  644. X    case $dist in
  645. X    h)
  646. X    $cat <<'EOH'
  647. X
  648. The Distribution line may be used to limit the distribution of an article
  649. to some subset of the systems that would receive the article based only on
  650. the Newsgroups line.  For example, if you want to sell your car in talk.auto,
  651. and you live in New Jersey, you might want to put "nj" on the Distribution
  652. line to avoid advertising in California, which has enough problems of its own.
  653. The actual area designators to use depend on where you are, of course.
  654. XEOH
  655. X    ;;
  656. X    ''|$loc*|$org*|$city*|$state*|$cntry*|$cont*|$defdist)
  657. X    ;;
  658. X    world*|comp*|news*|sci*|rec*|misc*|soc*|talk*|alt*)
  659. X    dist=''
  660. X    ;;
  661. X    *)  
  662. X    if $test -f $lib/distributions && \
  663. X      $egrep "^$dist[     ]" $lib/distributions >$tmpart && \
  664. X      $test -s $tmpart; then
  665. X        : null
  666. X    else
  667. X        $echo "Unrecognized distribution prefix--type h for help, CR to use anyway."
  668. X        defdist=$dist
  669. X        dist=h
  670. X    fi
  671. X    ;;
  672. X    esac
  673. done
  674. X
  675. follow=""
  676. X
  677. X# LCP 16-Oct-91 Subject line is required.  Make it a little more
  678. X# difficult to omit.  Added "while : ; do", ... "done", and "if"
  679. X# at end of while loop.
  680. while :
  681. do
  682. X  case $# in
  683. X  0)
  684. X    title=h
  685. X    while $test "$title" = h ; do
  686. X    $echo ""
  687. X    $echo $n "Title/Subject: $c"
  688. X    read title
  689. X    case $title in
  690. X    h)
  691. X        $cat <<'EOH'
  692. X
  693. Type the title for your article.  Please make it as informative as possible
  694. X(within reason) so that people who aren't interested won't have to read the
  695. article to find out they aren't interested.  This includes marking movie
  696. spoilers as (spoiler), and rotated jokes as (rot 13).
  697. XEOH
  698. X    ;;
  699. X    esac
  700. X    done
  701. X    ;;
  702. X  *)
  703. X    title="$*"
  704. X    # LCP 16-Oct-91 Added "set" and "shift".  Must insure $# is 0
  705. X    # in case the title is all white space and we make another
  706. X    # pass thru this loop.
  707. X    set X
  708. X    shift
  709. X    ;;
  710. X  esac
  711. X  if expr "X$title" : "^X[    ]*$" > /dev/null 2>&1
  712. X  then
  713. X    $cat <<'EOH'
  714. X
  715. Articles without a "Subject:" line will not be accepted by the News
  716. system.  Please give a Title/Subject line for your article.
  717. XEOH
  718. X  else
  719. X     break
  720. X  fi
  721. done
  722. X
  723. X
  724. X# now build a file with a header for them to edit
  725. X
  726. set X ${USER-${LOGNAME-`who am i`}}
  727. shift
  728. logname=$1
  729. case $logname in
  730. X*!*) logname=`expr "$logname" : '!\(.*\)$'` ;;
  731. esac
  732. case ${NAME-$nametype} in
  733. bsd)
  734. X    if $test "$ypmatch" != ""; then
  735. X        fullname=`$ypmatch $logname passwd 2>/dev/null | $sed -e "s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*"'$'"/\1/"`
  736. X    elif $test "$nidump" != ""; then
  737. X        fullname=`$nidump passwd / | $sed -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*"'$'"/\1/" -e "q" -e "}" -e "d"`
  738. X    fi
  739. X     if $test "$fullname" = ""; then
  740. X        fullname=`$sed </etc/passwd -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^,:;]*\).*"'$'"/\1/" -e "q" -e "}" -e "d"`
  741. X    fi
  742. X    case $fullname in
  743. X    *'&'*) : GACK
  744. X    lname=`$echo $logname | $tr 'a-z' 'A-Z'`
  745. X    lname=`$echo $lname $logname | $sed 's/^\(.\)[^ ]* ./\1/'`
  746. X    fullname=`$echo "$fullname" | $sed "s/&/${lname}/"`
  747. X    ;;
  748. X    esac
  749. X    ;;
  750. usg)
  751. X    if $test "$ypmatch" != ""; then
  752. X        fullname=`$ypmatch $logname passwd 2>/dev/null | $sed -e "s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^(:]*\).*"'$'"/\1/" -e "s/^.*-//" -e "q"`
  753. X    fi
  754. X     if $test "$fullname" = ""; then
  755. X    fullname=`$sed </etc/passwd -e "/^$logname:/{s/^[^:]*:[^:]*:[^:]*:[^:]*:\([^(:]*\).*"'$'"/\1/" -e "s/^.*-//" -e "q" -e "}" -e "d"`
  756. X    fi
  757. X    ;;
  758. X*)
  759. X    fullname=${NAME-`$cat $dotdir/.fullname`}
  760. X    ;;
  761. esac
  762. X
  763. case $orgname in
  764. X/*) orgname=`$cat $orgname` ;;
  765. esac
  766. X
  767. X$sed -e '/^Reply-To: $/d' > $tmpart <<EOHeader
  768. Newsgroups: $ng
  769. Subject: $title
  770. Summary: 
  771. Reply-To: $REPLYTO
  772. XFollowup-To: $follow
  773. Distribution: $dist
  774. Organization: $orgname
  775. Keywords: 
  776. X
  777. XEOHeader
  778. X
  779. X!NO!SUBS!
  780. case "$isrrn" in
  781. define) sed < Pnews.header -e '/^#NORMAL/d' > Pnews.h.new ;;
  782. X*)  sed < Pnews.header -e '/^#NORMAL/s/^#NORMAL//' > Pnews.h.new ;;
  783. esac
  784. mv Pnews.h.new Pnews.header
  785. X$eunicefix Pnews.header
  786. END_OF_FILE
  787. if test 17117 -ne `wc -c <'Pnews.SH'`; then
  788.     echo shar: \"'Pnews.SH'\" unpacked with wrong size!
  789. fi
  790. # end of 'Pnews.SH'
  791. fi
  792. if test -f 'help.c' -a "${1}" != "-c" ; then 
  793.   echo shar: Will not clobber existing file \"'help.c'\"
  794. else
  795. echo shar: Extracting \"'help.c'\" \(16450 characters\)
  796. sed "s/^X//" >'help.c' <<'END_OF_FILE'
  797. X/* $Id: help.c,v 4.4.2.1 1991/12/01 18:05:42 sob PATCH_2 sob $
  798. X *
  799. X * $Log: help.c,v $
  800. X * Revision 4.4.2.1  1991/12/01  18:05:42  sob
  801. X * Patchlevel 2 changes
  802. X *
  803. X * Revision 4.4  1991/09/09  20:18:23  sob
  804. X * release 4.4
  805. X *
  806. X *
  807. X * 
  808. X */
  809. X/* This software is Copyright 1991 by Stan Barber. 
  810. X *
  811. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  812. X * use this software as long as: there is no monetary profit gained
  813. X * specifically from the use or reproduction of this software, it is not
  814. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  815. X * included prominently in any copy made. 
  816. X *
  817. X * The author make no claims as to the fitness or correctness of this software
  818. X * for any use whatsoever, and it is provided as is. Any use of this software
  819. X * is at the user's own risk. 
  820. X */
  821. X
  822. X#include "EXTERN.h"
  823. X#include "common.h"
  824. X#include "rn.h"
  825. X#include "term.h"
  826. X#include "INTERN.h"
  827. X#include "help.h"
  828. X
  829. void
  830. help_init()
  831. X{
  832. X    ;
  833. X}
  834. X
  835. int
  836. help_page()
  837. X{
  838. X    int cmd;
  839. X
  840. X#ifdef PAGERHELP
  841. X    doshell(sh,filexp(PAGERHELP));
  842. X#else
  843. X    page_init();
  844. X    if ((cmd = print_lines("\
  845. Paging commands:\n\
  846. X",STANDOUT)) ||
  847. X    (cmd = print_lines("\n\
  848. SP    Display the next page.\n\
  849. x    Display the next page decrypted (rot13).\n\
  850. d    Display half a page more.\n\
  851. CR    Display one more line.\n\
  852. X^R,v,^X    Restart the current article (v=verbose header, ^X=rot13).\n\
  853. X",NOMARKING)) ||
  854. X    (cmd = print_lines("\
  855. b    Back up one page.\n\
  856. X^L,X    Refresh the screen (X=rot13).\n\
  857. X",NOMARKING)) ||
  858. X#ifdef USETHREADS
  859. X    (cmd = print_lines("\
  860. t    Display the entire article tree and all its subjects.\n\
  861. X",NOMARKING)) ||
  862. X#endif
  863. X    (cmd = print_lines("\
  864. g pat    Go to (search forward within article for) pattern.\n\
  865. G    Search again for current pattern within article.\n\
  866. X^G    Search for next line beginning with \"Subject:\".\n\
  867. TAB    Search for next line beginning with a different character.\n\
  868. q    Quit the pager, go to end of article.  Leave article read or unread.\n\
  869. j    Junk this article (mark it read).  Goes to end of article.\n\
  870. X\n\
  871. X",NOMARKING)) ||
  872. X    (cmd = print_lines("\
  873. The following commands skip the rest of the current article, then behave\n\
  874. just as if typed to the 'What next?' prompt at the end of the article:\n\
  875. X",STANDOUT)) ||
  876. X    (cmd = print_lines("\n\
  877. n    Scan forward for next unread article.\n\
  878. N    Go to next article.\n\
  879. X^N    Scan forward for next unread article with same title.\n\
  880. p,P,^P    Same as n,N,^N, only going backwards.\n\
  881. X-    Go to previously displayed article.\n\
  882. X",NOMARKING)) ||
  883. X#ifdef USETHREADS
  884. X    (cmd = print_lines("\
  885. X<,>    Browse the previous/next selected thread.  If no threads are selected,\n\
  886. X    all threads that had unread news upon entry to the group are considered\n\
  887. X    selected for browsing.  Entering an empty group browses all threads.\n\
  888. X[,],{,} Go to parent/child/root/leaf in thread.\n\
  889. X\n\
  890. X",NOMARKING)) ||
  891. X#endif
  892. X    (cmd = print_lines("\
  893. The following commands also take you to the end of the article.\n\
  894. Type h at end of article for a description of these commands:\n\
  895. X",STANDOUT)) ||
  896. X#ifdef USETHREADS
  897. X    (cmd = print_lines("\
  898. X    # $ & / = ? c C f F k K ^K J , m M number e r R ^R s S u U v w W Y ^ |\n\
  899. X\n\
  900. X(To return to the middle of the article after one of these commands, type ^L.)\n\
  901. X",NOMARKING)) )
  902. X#else
  903. X    (cmd = print_lines("\
  904. X    # $ & / = ? c C f F k K ^K m M number e r R ^R s S u v w W Y ^ |\n\
  905. X\n\
  906. X(To return to the middle of the article after one of these commands, type ^L.)\n\
  907. X",NOMARKING)) )
  908. X#endif
  909. X    return cmd;
  910. X#endif
  911. X    return 0;
  912. X}
  913. X
  914. int
  915. help_art()
  916. X{
  917. X    int cmd;
  918. X#ifdef ARTHELP
  919. X    doshell(sh,filexp(ARTHELP));
  920. X#else
  921. X    page_init();
  922. X    if ((cmd = print_lines("\
  923. Article Selection commands:\n\
  924. X",STANDOUT)) ||
  925. X#ifdef USETHREADS
  926. X    (cmd = print_lines("\n\
  927. n,SP    Find next unread article (follows discussion-tree in threaded groups).\n\
  928. X",NOMARKING)) ||
  929. X#else
  930. X    (cmd = print_lines("\n\
  931. n,SP    Scan forward for next unread article.\n\
  932. X",NOMARKING)) ||
  933. X#endif
  934. X    (cmd = print_lines("\
  935. N    Go to next article.\n\
  936. X^N    Scan forward for next unread article with same subject.\n\
  937. p,P,^P    Same as n,N,^N, only going backwards.\n\
  938. X-    Go to previously displayed article.\n\
  939. X",NOMARKING)) ||
  940. X#ifdef USETHREADS
  941. X    (cmd = print_lines("\
  942. X<,>    Browse the previous/next selected thread.  If no threads are selected,\n\
  943. X    all threads that had unread news upon entry to the group are considered\n\
  944. X    selected for browsing.  Entering an empty group browses all threads.\n\
  945. X[,]    Go to article's parent/child.\n\
  946. X{,}    Go to tree's root/leaf.\n\
  947. t    Display the entire article tree and all its subjects.\n\
  948. X",NOMARKING)) ||
  949. X#endif
  950. X    (cmd = print_lines("\
  951. number    Go to specified article.\n\
  952. range{,range}:command{:command}\n\
  953. X    Apply one or more commands to one or more ranges of articles.\n\
  954. X    Ranges are of the form: number | number-number.  You may use . for\n\
  955. X    the current article, and $ for the last article.\n\
  956. X",NOMARKING)) ||
  957. X#ifdef USETHREADS
  958. X    (cmd = print_lines("\
  959. X     Valid commands are: e, j, m, M, s, S, t, T, |, +, and -.\n\
  960. X:cmd    Perform a command on all the selected articles.\n\
  961. X",NOMARKING)) ||
  962. X#else
  963. X    (cmd = print_lines("\
  964. X     Valid commands are: e, j, m, M, s, S, and |.\n\
  965. X",NOMARKING)) ||
  966. X#endif
  967. X    (cmd = print_lines("\
  968. X/pattern/modifiers\n\
  969. X    Scan forward for article containing pattern in the subject line.\n\
  970. X    (Use ?pat? to scan backwards; append h to scan headers, a to scan\n\
  971. X    entire articles, r to scan read articles, c to make case sensitive.)\n\
  972. X",NOMARKING)) ||
  973. X    (cmd = print_lines("\
  974. X/pattern/modifiers:command{:command}\n\
  975. X    Apply one or more commands to the set of articles matching pattern.\n\
  976. X    Use a K modifier to save entire command to the KILL file for this\n\
  977. X    newsgroup.  Commands m and M, if first, imply an r modifier.\n\
  978. X     Valid commands are the same as for the range command.\n\
  979. X",NOMARKING)) ||
  980. X    (cmd = print_lines("\
  981. f,F    Submit a followup article (F = include this article).\n\
  982. r,R    Reply through net mail (R = include this article).\n\
  983. e dir{|command}\n\
  984. X    Extract to directory using /bin/sh, uudecode, unship, or command.\n\
  985. s ...    Save to file or pipe via sh.\n\
  986. S ...    Save via preferred shell.\n\
  987. w,W    Like s and S but save without the header.\n\
  988. X| ...    Same as s|...\n\
  989. X",NOMARKING)) ||
  990. X    (cmd = print_lines("\
  991. C    Cancel this article, if yours.\n\
  992. X^R,v    Restart article (v=verbose).\n\
  993. X^X    Restart article, rot13 mode.\n\
  994. c    Catch up (mark all articles as read).\n\
  995. b    Back up one page.\n\
  996. X^L    Refresh the screen.  You can get back to the pager with this.\n\
  997. XX    Refresh screen in rot13 mode.\n\
  998. X",NOMARKING)) ||
  999. X    (cmd = print_lines("\
  1000. X^    Go to first unread article.  Disables subject search mode.\n\
  1001. X$    Go to end of newsgroup.  Disables subject search mode.\n\
  1002. X",NOMARKING)) ||
  1003. X    (cmd = print_lines("#       Print last article number.\n\
  1004. X&    Print current values of command-line switches.\n\
  1005. X&switch {switch}\n\
  1006. X    Set or unset more switches.\n\
  1007. X&&    Print current macro definitions.\n\
  1008. X&&def    Define a new macro.\n\
  1009. j    Junk this article (mark it read).  Stays at end of article.\n\
  1010. X",NOMARKING)) ||
  1011. X    (cmd = print_lines("\
  1012. m    Mark article as still unread.\n\
  1013. M    Mark article as still unread upon exiting newsgroup or Y command.\n\
  1014. Y    Yank back articles marked temporarily read via M.\n\
  1015. k    Kill current subject (mark articles as read).\n\
  1016. X",NOMARKING)) ||
  1017. X#ifdef USETHREADS
  1018. X    (cmd = print_lines("\
  1019. X,    Mark current article and its replies as read.\n\
  1020. J    Junk entire thread (mark all subjects as read in this thread).\n\
  1021. T    Trash current thread (like 'J'), and save command in KILL file.\n\
  1022. X",NOMARKING)) ||
  1023. X#endif
  1024. X    (cmd = print_lines("\
  1025. K    Mark current subject as read, and save command in KILL file.\n\
  1026. X^K    Edit local KILL file (the one for this newsgroup).\n\
  1027. X=    List subjects of unread articles.\n\
  1028. X",NOMARKING)) ||
  1029. X#ifdef USETHREADS
  1030. X    (cmd = print_lines("\
  1031. X+    Enter thread selection mode.\n\
  1032. U    Unread some news -- prompts for thread, subthread, all, or select.\n\
  1033. X",NOMARKING)) ||
  1034. X#endif
  1035. X    (cmd = print_lines("\
  1036. u    Unsubscribe from this newsgroup.\n\
  1037. q    Quit this newsgroup for now.\n\
  1038. Q    Quit newsgroup, staying at current newsgroup.\n\
  1039. X",NOMARKING)) )
  1040. X    return cmd;
  1041. X#endif
  1042. X    return 0;
  1043. X}
  1044. X
  1045. int
  1046. help_ng()
  1047. X{
  1048. X    int cmd;
  1049. X#ifdef NGHELP
  1050. X    doshell(sh,filexp(NGHELP));
  1051. X#else
  1052. X    page_init();
  1053. X    if (cmd = print_lines("\
  1054. Newsgroup Selection commands:\n\
  1055. X",STANDOUT) )
  1056. X    return cmd;
  1057. X    if (ng != nextrcline) {
  1058. X    if ((cmd = print_lines("\
  1059. X\n\
  1060. y,SP    Do this newsgroup now.\n\
  1061. X.cmd    Do this newsgroup, executing cmd as first command.\n\
  1062. X",NOMARKING)) ||
  1063. X#ifdef USETHREADS
  1064. X    (cmd = print_lines("\
  1065. X+    Enter this newsgroup through the thread selector (like typing .+<CR>).\n\
  1066. X",NOMARKING)) ||
  1067. X#endif
  1068. X    (cmd = print_lines("\
  1069. X=    Start this newsgroup, but list subjects before reading articles.\n\
  1070. X",NOMARKING)) ||
  1071. X#ifdef USETHREADS
  1072. X    (cmd = print_lines("\
  1073. U    Enter this newsgroup by way of the \"Set unread?\" prompt.\n\
  1074. X",NOMARKING)) ||
  1075. X#endif
  1076. X    (cmd = print_lines("\
  1077. u    Unsubscribe from this newsgroup.\n\
  1078. X",NOMARKING)) )
  1079. X        return cmd;
  1080. X    }
  1081. X    if ((cmd = print_lines("\
  1082. c    Catch up (mark this newsgroup all read).\n\
  1083. A    Abandon read/unread changes to this newsgroup since you started trn.\n\
  1084. X\n\
  1085. n    Go to the next newsgroup with unread news.\n\
  1086. N    Go to the next newsgroup.\n\
  1087. p    Go to the previous newsgroup with unread news.\n\
  1088. P    Go to the previous newsgroup.\n\
  1089. X",NOMARKING)) ||
  1090. X    (cmd = print_lines("\
  1091. X-    Go to the previously displayed newsgroup.\n\
  1092. X1    Go to the first newsgroup.\n\
  1093. X^    Go to the first newsgroup with unread news.\n\
  1094. X$    Go to the last newsgroup.\n\
  1095. X",NOMARKING)) ||
  1096. X    (cmd = print_lines("\
  1097. g name    Go to the named newsgroup.  Subscribe to new newsgroups this way too.\n\
  1098. X/pat    Search forward for newsgroup matching pattern.\n\
  1099. X?pat    Search backward for newsgroup matching pattern.\n\
  1100. X    (Use * and ? style patterns.  Append r to include read newsgroups.)\n\
  1101. X",NOMARKING)) ||
  1102. X    (cmd = print_lines("\
  1103. l pat    List unsubscribed newsgroups containing pattern.\n\
  1104. m name    Move named newsgroup elsewhere (no name moves current newsgroup).\n\
  1105. o pat    Only display newsgroups matching pattern.  Omit pat to unrestrict.\n\
  1106. a pat    Like o, but also scans for unsubscribed newsgroups matching pattern.\n\
  1107. L    List current .newsrc.\n\
  1108. X",NOMARKING)) ||
  1109. X    (cmd = print_lines("\
  1110. X&    Print current command-line switch settings.\n\
  1111. X&switch {switch}\n\
  1112. X    Set (or unset) more command-line switches.\n\
  1113. X&&    Print current macro definitions.\n\
  1114. X&&def    Define a new macro.\n\
  1115. X!cmd    Shell escape.\n\
  1116. X",NOMARKING)) ||
  1117. X    (cmd = print_lines("\
  1118. q    Quit trn.\n\
  1119. x    Quit, restoring .newsrc to its state at startup of trn.\n\
  1120. X^K    Edit the global KILL file.  Use commands like /pattern/j to suppress\n\
  1121. X    pattern in every newsgroup.\n\
  1122. v    Print version.\n\
  1123. X",NOMARKING)) )
  1124. X    return cmd;
  1125. X#endif
  1126. X#ifdef PUSHBACK
  1127. X    if (cmd = get_anything())
  1128. X    return cmd;
  1129. X    show_macros();
  1130. X#endif
  1131. X    return 0;
  1132. X}
  1133. X
  1134. X#ifdef ESCSUBS
  1135. int
  1136. help_subs()
  1137. X{
  1138. X    int cmd;
  1139. X#ifdef SUBSHELP
  1140. X    doshell(sh,filexp(SUBSHELP));
  1141. X#else
  1142. X    page_init();
  1143. X    if ((cmd = print_lines("\
  1144. Valid substitutions are:\n\
  1145. X",STANDOUT)) ||
  1146. X    (cmd = print_lines("\
  1147. X\n\
  1148. a    Current article number\n\
  1149. A    Full name of current article (%P/%c/%a)\n\
  1150. b    Destination of last save command, often a mailbox\n\
  1151. B    Bytes to ignore at beginning of last saved article\n\
  1152. X",NOMARKING)) ||
  1153. X    (cmd = print_lines("\
  1154. c    Current newsgroup, directory form\n\
  1155. C    Current newsgroup, dot form\n\
  1156. d    Full name of newsgroup directory (%P/%c)\n\
  1157. D    Distribution line from current article\n\
  1158. e    The last command executed to extract data from an article\n\
  1159. XE    The last extraction directory\n\
  1160. X",NOMARKING)) ||
  1161. X    (cmd = print_lines("\
  1162. f    Who the current article is from\n\
  1163. XF    Newsgroups to followup to (from Newsgroups and Followup-To)\n\
  1164. h    (This help message)\n\
  1165. H    Host name (yours)\n\
  1166. i    Message-I.D. line from current article, with <>\n\
  1167. I    Reference indicator mark (see -F switch)\n\
  1168. X",NOMARKING)) ||
  1169. X    (cmd = print_lines("\
  1170. l    News administrator's login name, if any\n\
  1171. L    Login name (yours)\n\
  1172. X",NOMARKING)) ||
  1173. X#ifdef USETHREADS
  1174. X    (cmd = print_lines("\
  1175. m    Current mode, first letter of (init,newsgroup,thread,article,pager,\n\
  1176. X        unread,Add,Catchup,Delete-bogus,Mailbox,Resubscribe)\n\
  1177. X",NOMARKING)) ||
  1178. X#else
  1179. X    (cmd = print_lines("\
  1180. m    Current mode, first letter of (init, newsgroup, article, pager,\n\
  1181. X        Add, Catchup, Delete bogus, Mailbox, Resubscribe)\n\
  1182. X",NOMARKING)) ||
  1183. X#endif
  1184. X    (cmd = print_lines("\
  1185. M    Number of article marked with M\n\
  1186. n    Newsgroups from current article\n\
  1187. N    Full name (yours)\n\
  1188. o    Organization (yours)\n\
  1189. O    Original working directory (where you ran trn from)\n\
  1190. X",NOMARKING)) ||
  1191. X    (cmd = print_lines("\
  1192. p    Your private news directory (from -d)\n\
  1193. P    Public news spool directory\n\
  1194. r    Last reference (parent article id)\n\
  1195. R    References list for followup article\n\
  1196. X",NOMARKING)) ||
  1197. X    (cmd = print_lines("\
  1198. s    Subject, with all Re's and (nf)'s stripped off\n\
  1199. S    Subject, with one Re stripped off\
  1200. t    New To line derived from From and Reply-To (Internet format)\n\
  1201. T    New To line derived from Path\n\
  1202. u    Number of unread articles\n\
  1203. X",NOMARKING)) ||
  1204. X#ifdef USETHREADS
  1205. X    (cmd = print_lines("\
  1206. U    Number of unread articles not counting the current article (when\n\
  1207. X    threads are selected, the count only reflects selected articles)\n\
  1208. v    The number of extra (unselected) articles, not counting the current\n\
  1209. X    one if it is unselected\n\
  1210. w    Mthreads' tmp directory\n\
  1211. W    Where thread files are saved\n\
  1212. x    News library directory\n\
  1213. XX    Trn library directory\n\
  1214. z    Length of current article in bytes\n\
  1215. Z    Number of selected threads\n\
  1216. X",NOMARKING)) ||
  1217. X#else
  1218. X    (cmd = print_lines("\
  1219. U    Number of unread articles not counting the current article\n\
  1220. x    News library directory\n\
  1221. XX    Trn library directory\n\
  1222. z    Length of current article in bytes\n\
  1223. X",NOMARKING)) ||
  1224. X#endif
  1225. X    (cmd = print_lines("\
  1226. X~    Your home directory\n\
  1227. X.    Directory containing . files\n\
  1228. X#    A counter in multi-article saves\n\
  1229. X$    Current process number\n\
  1230. X/    Last search string\n\
  1231. XESC    Run preceding command through % interpretation\n\
  1232. X",NOMARKING)) )
  1233. X    return cmd;
  1234. X#endif
  1235. X    return 0;
  1236. X}
  1237. X#endif
  1238. X
  1239. X#ifdef USETHREADS
  1240. int
  1241. help_select()
  1242. X{
  1243. X    int cmd;
  1244. X
  1245. X    page_init();
  1246. X    if ((cmd = print_lines("\
  1247. Thread selection commands:\n\
  1248. X",STANDOUT)) ||
  1249. X    (cmd = print_lines("\n\
  1250. a-z,0-9    Select/deselect the discussion thread by its letter or number.  By\n\
  1251. X    default the letters h, k, m, n, p, q and y are omitted.\n\
  1252. SP    Perform the default command (usually > or Z).\n\
  1253. CR    Start reading.  Selects the current thread if none are selected.\n\
  1254. Z,TAB    Start reading.  If no articles are selected, read everything.\n\
  1255. y, '.'    Toggle the current thread's selection.\n\
  1256. k, ','    Mark the current thread as killed.\n\
  1257. X",NOMARKING)) ||
  1258. X    (cmd = print_lines("\
  1259. m, \\    Unmark the current thread.\n\
  1260. X-    Set a range, as in 2 - 5.  Repeats the last marking action.\n\
  1261. X@    Toggle all visible thread selections.\n\
  1262. n, ]    Move down to the next thread.\n\
  1263. p, [    Move up to the previous thread.\n\
  1264. X<, >    Go to previous/next page.\n\
  1265. X^, $    Go to first/last page.\n\
  1266. X",NOMARKING)) ||
  1267. X    (cmd = print_lines("\
  1268. XX    Mark all unselected articles as read and start reading.\n\
  1269. D    Mark unselected articles on the current page as read.  Start\n\
  1270. X    reading if articles were selected, else go to next page.\n\
  1271. J    Junk all selected articles (mark them as read).\n\
  1272. X^K    Edit local KILL file (the one for this newsgroup).\n\
  1273. X:cmd    Perform a command on all the selected articles.\n\
  1274. X",NOMARKING)) ||
  1275. X    (cmd = print_lines("\
  1276. X/pattern/modifiers\n\
  1277. X    Scan all articles for a subject containing pattern.\n\
  1278. X    (Append h to scan headers, a to scan entire articles, c to make case\n\
  1279. X    sensitive, r to scan read articles (assumed when you are selecting\n\
  1280. X    read articles to set unread.)\n\
  1281. X/pattern/modifiers:command{:command}\n\
  1282. X    Apply one or more commands to the set of articles matching pattern.\n\
  1283. X",NOMARKING)) ||
  1284. X    (cmd = print_lines("\
  1285. X    Use a K modifier to save entire command to the KILL file for this\n\
  1286. X    newsgroup.  Commands m and M, if first, imply an r modifier.\n\
  1287. X     Valid commands are: e, E, j, m, M, s, S, t, T, !, =, ',' and the\n\
  1288. X    thread selection commands: + and -.\n\
  1289. N    Leave this group as-is and go on to the next.\n\
  1290. U    Switch between selecting read/unread articles.\n\
  1291. L    Switch the current display mode between a terse mode without\n\
  1292. X    authors and a short and long mode with authors.\n\
  1293. X",NOMARKING)) ||
  1294. X    (cmd = print_lines("\
  1295. X&    View or set command line switches.\n\
  1296. X&&    View or set macro definitions.\n\
  1297. X!cmd    Escape to a subshell.\n\
  1298. q    Quit selection mode.\n\
  1299. Q    Quit group and return to news group selection prompt for this group.\n\
  1300. X",NOMARKING)) )
  1301. X    return cmd;
  1302. X    return 0;
  1303. X}
  1304. X#endif
  1305. END_OF_FILE
  1306. if test 16450 -ne `wc -c <'help.c'`; then
  1307.     echo shar: \"'help.c'\" unpacked with wrong size!
  1308. fi
  1309. # end of 'help.c'
  1310. fi
  1311. if test -f 'mt-read.c' -a "${1}" != "-c" ; then 
  1312.   echo shar: Will not clobber existing file \"'mt-read.c'\"
  1313. else
  1314. echo shar: Extracting \"'mt-read.c'\" \(15542 characters\)
  1315. sed "s/^X//" >'mt-read.c' <<'END_OF_FILE'
  1316. X/* $Id: mt-read.c,v 4.4.3.1 1991/11/22 04:12:15 davison Trn $
  1317. X**
  1318. X** $Log: mt-read.c,v $
  1319. X** Revision 4.4.3.1  1991/11/22  04:12:15  davison
  1320. X** Trn Release 2.0
  1321. X** 
  1322. X*/
  1323. X
  1324. X#include "EXTERN.h"
  1325. X#include "common.h"
  1326. X#include "threads.h"
  1327. X#include "mthreads.h"
  1328. X
  1329. extern char *lib, *rnlib, *mtlib, *spool, *threaddir, *homedir;
  1330. extern long first;
  1331. X
  1332. static FILE *fp_in;
  1333. X
  1334. void tweak_roots ANSI((void));
  1335. void wrap_it_up ANSI((int));
  1336. X
  1337. X/* Attempt to open the thread file.  If it's there, only grab the totals
  1338. X** from the start of the file.  This should give them enough information
  1339. X** to decide if they need to read the whole thing into memory.
  1340. X*/
  1341. int
  1342. init_data(filename)
  1343. char *filename;
  1344. X{
  1345. X    root_root = Null(ROOT*);
  1346. X    author_root = Null(AUTHOR*);
  1347. X    unk_domain.ids = Nullart;
  1348. X    unk_domain.link = Null(DOMAIN*);
  1349. X
  1350. X    if (filename && (fp_in = fopen(filename, FOPEN_RB)) != Nullfp) {
  1351. X#ifdef SETBUFFER
  1352. X    setbuffer(fp_in, rwbuf, RWBUFSIZ);
  1353. X#else
  1354. X# ifdef SETVBUF
  1355. X    setvbuf(fp_in, rwbuf, _IOFBF, RWBUFSIZ);
  1356. X# endif
  1357. X#endif
  1358. X    if (fread((char*)&total,1,sizeof (TOTAL),fp_in) == sizeof (TOTAL)) {
  1359. X#ifdef TMPTHREAD
  1360. X        lp_bmap(&total.first, 4);
  1361. X        wp_bmap(&total.root, 5);
  1362. X#endif
  1363. X
  1364. X        /* If the data looks ok, return success. */
  1365. X        if (total.last - total.first >= 0 && total.author > 0
  1366. X         && total.article > 0 && total.subject > 0 && total.domain > 0
  1367. X         && total.subject <= total.article && total.author <= total.article
  1368. X         && total.root <= total.article && total.domain <= total.article
  1369. X         && total.string1 > 0 && total.string2 > 0) {
  1370. X        return 1;
  1371. X        }
  1372. X    }
  1373. X    bzero(&total, sizeof (TOTAL));
  1374. X    total.first = first;
  1375. X    total.last = first - 1;
  1376. X    return 1;
  1377. X    }
  1378. X    bzero(&total, sizeof (TOTAL));
  1379. X    return 0;
  1380. X}
  1381. X
  1382. X/* They want everything.  Read in the packed information and transform it
  1383. X** into a set of linked structures that is easily manipulated.
  1384. X*/
  1385. int
  1386. read_data()
  1387. X{
  1388. X    /* If this is an empty thread file, simply return success. */
  1389. X    if (!total.root) {
  1390. X    fclose(fp_in);
  1391. X    return 1;
  1392. X    }
  1393. X
  1394. X    if (read_authors()
  1395. X     && read_subjects()
  1396. X     && read_roots()
  1397. X     && read_articles()
  1398. X     && read_ids())
  1399. X    {
  1400. X    tweak_roots();
  1401. X    fclose(fp_in);
  1402. X    return 1;
  1403. X    }
  1404. X    /* Something failed.  Safefree takes care of checking if some items
  1405. X    ** were already freed.  Any partially-allocated structures were freed
  1406. X    ** before we got here.  All other structures are cleaned up.
  1407. X    */
  1408. X    if (root_root) {
  1409. X    register ROOT *root, *next_root;
  1410. X    register SUBJECT *subj, *next_subj;
  1411. X
  1412. X    for (root = root_root; root; root = next_root) {
  1413. X        for (subj = root->subjects; subj; subj = next_subj) {
  1414. X        next_subj = subj->link;
  1415. X        free(subj->str);
  1416. X        free(subj);
  1417. X        }
  1418. X        next_root = root->link;
  1419. X        free(root);
  1420. X    }
  1421. X    root_root = Null(ROOT*);
  1422. X    }
  1423. X    if (author_array) {
  1424. X    register int count;
  1425. X
  1426. X    for (count = total.author; count--;) {
  1427. X        free(author_array[count]->name);
  1428. X        free(author_array[count]);
  1429. X    }
  1430. X    safefree(&author_array);
  1431. X    author_root = Null(AUTHOR*);
  1432. X    }
  1433. X    if (article_array) {
  1434. X    register int count;
  1435. X
  1436. X    for (count = total.article; count--;) {
  1437. X        free(article_array[count]);
  1438. X    }
  1439. X    safefree(&article_array);
  1440. X    }
  1441. X    safefree(&strings);
  1442. X    safefree(&subject_cnts);
  1443. X    safefree(&subject_array);
  1444. X    safefree(&author_cnts);
  1445. X    safefree(&root_array);
  1446. X    safefree(&ids);
  1447. X    unk_domain.ids = Nullart;
  1448. X    unk_domain.link = Null(DOMAIN*);
  1449. X    fclose(fp_in);
  1450. X    return 0;
  1451. X}
  1452. X
  1453. X/* They don't want to read the data.  Close the file if we opened it.
  1454. X*/
  1455. void
  1456. dont_read_data(open_flag)
  1457. int open_flag;        /* 0 == not opened, 1 == open failed, 2 == open */
  1458. X{
  1459. X    if (open_flag == 2) {
  1460. X    fclose(fp_in);
  1461. X    bzero(&total, sizeof (TOTAL));
  1462. X    }
  1463. X}
  1464. X
  1465. X#define give_string_to(dest)    /* Comment for makedepend to     \
  1466. X                ** ignore the backslash above */ \
  1467. X{\
  1468. X    register MEM_SIZE len = strlen(string_ptr) + 1;\
  1469. X    dest = safemalloc(len);\
  1470. X    bcopy(string_ptr, dest, (int)len);\
  1471. X    string_ptr += len;\
  1472. X}
  1473. X
  1474. char *subject_strings, *string_end;
  1475. X
  1476. X/* The author information is an array of use-counts, followed by all the
  1477. X** null-terminated strings crammed together.  The subject strings are read
  1478. X** in at the same time, since they are appended to the end of the author
  1479. X** strings.
  1480. X*/
  1481. int
  1482. read_authors()
  1483. X{
  1484. X    register int count, author_tally;
  1485. X    register char *string_ptr;
  1486. X    register WORD *authp;
  1487. X    register AUTHOR *author, *last_author, **author_ptr;
  1488. X
  1489. X    if (!read_item(&author_cnts, (MEM_SIZE)total.author * sizeof (WORD))
  1490. X     || !read_item(&strings, total.string1)) {
  1491. X    /* (Error already logged.) */
  1492. X    return 0;
  1493. X    }
  1494. X#ifdef TMPTHREAD
  1495. X    wp_bmap(author_cnts, total.author);
  1496. X#endif
  1497. X
  1498. X    string_ptr = strings;
  1499. X    string_end = string_ptr + total.string1;
  1500. X    if (string_end[-1] != '\0') {
  1501. X    log_error("first string table is invalid.\n");
  1502. X    return 0;
  1503. X    }
  1504. X
  1505. X    /* We'll use this array to point each article at its proper author
  1506. X    ** (packed values are saved as indexes).
  1507. X    */
  1508. X    author_array = (AUTHOR**)safemalloc(total.author * sizeof (AUTHOR*));
  1509. X    author_ptr = author_array;
  1510. X
  1511. X    authp = author_cnts;
  1512. X
  1513. X    author_tally = 0;
  1514. X#ifndef lint
  1515. X    last_author = (AUTHOR*)&author_root;
  1516. X#else
  1517. X    last_author = Null(AUTHOR*);
  1518. X#endif
  1519. X    for (count = total.author; count; count--) {
  1520. X    if (string_ptr >= string_end) {
  1521. X        break;
  1522. X    }
  1523. X    *author_ptr++ = author = (AUTHOR*)safemalloc(sizeof (AUTHOR));
  1524. X    last_author->link = author;
  1525. X    give_string_to(author->name);
  1526. X    author_tally += *authp;
  1527. X    author->count = *authp++;
  1528. X    last_author = author;
  1529. X    }
  1530. X    last_author->link = Null(AUTHOR*);
  1531. X
  1532. X    subject_strings = string_ptr;
  1533. X
  1534. X    safefree(&author_cnts);
  1535. X
  1536. X    if (count || author_tally > total.article) {
  1537. X    log_error("author unpacking failed.\n");
  1538. X    for (; count < total.author; count++) {
  1539. X        free((*--author_ptr)->name);
  1540. X        free(*author_ptr);
  1541. X    }
  1542. X    safefree(&author_array);
  1543. X    return 0;
  1544. X    }
  1545. X    return 1;
  1546. X}
  1547. X
  1548. X/* The subject values consist of the crammed-together null-terminated strings
  1549. X** (already read in above) and the use-count array.  They were saved in the
  1550. X** order that the roots require while being unpacked.
  1551. X*/
  1552. int
  1553. read_subjects()
  1554. X{
  1555. X    if (!read_item(&subject_cnts, (MEM_SIZE)total.subject * sizeof (WORD))) {
  1556. X    /* (Error already logged.) */
  1557. X    return 0;
  1558. X    }
  1559. X#ifdef TMPTHREAD
  1560. X    wp_bmap(subject_cnts, total.subject);
  1561. X#endif
  1562. X    return 1;
  1563. X}
  1564. X
  1565. X/* Read in the packed root structures and recreate the linked list versions,
  1566. X** processing each root's subjects as we go.  Defer interpretation of article
  1567. X** offsets until we unpack the article structures.
  1568. X*/
  1569. int
  1570. read_roots()
  1571. X{
  1572. X    register int count, subj_tally;
  1573. X    register char *string_ptr;
  1574. X    register WORD *subjp;
  1575. X    ROOT *root, *last_root, **root_ptr;
  1576. X    SUBJECT *subject, *last_subject, **subj_ptr;
  1577. X    int ret;
  1578. X
  1579. X    /* Use this array when unpacking the article's subject offset. */
  1580. X    subject_array = (SUBJECT**)safemalloc(total.subject * sizeof (SUBJECT*));
  1581. X    subj_ptr = subject_array;
  1582. X    /* And this array points the article's root offset at the right spot. */
  1583. X    root_array = (ROOT**)safemalloc(total.root * sizeof (ROOT*));
  1584. X    root_ptr = root_array;
  1585. X
  1586. X    subjp = subject_cnts;
  1587. X    string_ptr = subject_strings;    /* string_end is already set */
  1588. X
  1589. X    subj_tally = 0;
  1590. X#ifndef lint
  1591. X    last_root = (ROOT*)&root_root;
  1592. X#else
  1593. X    last_root = Null(ROOT*);
  1594. X#endif
  1595. X    for (count = total.root; count--;) {
  1596. X    ret = fread((char*)&p_root, 1, sizeof (PACKED_ROOT), fp_in);
  1597. X    if (ret != sizeof (PACKED_ROOT)) {
  1598. X        log_error("failed root read -- %d bytes instead of %d.\n",
  1599. X        ret, sizeof (PACKED_ROOT));
  1600. X        return 0;
  1601. X    }
  1602. X#ifdef TMPTHREAD
  1603. X    lp_bmap(&p_root.root_num, 1);
  1604. X    wp_bmap(&p_root.articles, 3);
  1605. X#endif
  1606. X    if (p_root.articles < 0 || p_root.articles >= total.article
  1607. X     || subj_ptr - subject_array + p_root.subject_cnt > total.subject) {
  1608. X        log_error("root has invalid values.\n");
  1609. X        return 0;
  1610. X    }
  1611. X    *root_ptr++ = root = (ROOT*)safemalloc(sizeof (ROOT));
  1612. X    root->link = Null(ROOT*);
  1613. X    root->articles = Nullart;
  1614. X    root->seq = p_root.articles;
  1615. X    root->root_num = p_root.root_num;
  1616. X    root->thread_cnt = p_root.thread_cnt;
  1617. X    root->subject_cnt = p_root.subject_cnt;
  1618. X    last_root->link = root;
  1619. X    last_root = root;
  1620. X
  1621. X#ifndef lint
  1622. X    last_subject = (SUBJECT*)&root->subjects;
  1623. X#else
  1624. X    last_subject = Null(SUBJECT*);
  1625. X#endif
  1626. X    while (p_root.subject_cnt--) {
  1627. X        if (string_ptr >= string_end) {
  1628. X        log_error("error unpacking subject strings.\n");
  1629. X        last_subject->link = Null(SUBJECT*);
  1630. X        return 0;
  1631. X        }
  1632. X        *subj_ptr++ = subject = (SUBJECT*)safemalloc(sizeof (SUBJECT));
  1633. X        last_subject->link = subject;
  1634. X        give_string_to(subject->str);
  1635. X        subj_tally += *subjp;
  1636. X        subject->count = *subjp++;
  1637. X        last_subject = subject;
  1638. X    }
  1639. X    last_subject->link = Null(SUBJECT*);
  1640. X    }
  1641. X    if (subj_ptr != subject_array + total.subject
  1642. X     || subj_tally > total.article
  1643. X     || string_ptr != string_end) {
  1644. X    log_error("subject data is invalid.\n");
  1645. X    return 0;
  1646. X    }
  1647. X    safefree(&subject_cnts);
  1648. X    safefree(&strings);
  1649. X
  1650. X    return 1;
  1651. X}
  1652. X
  1653. bool invalid_data;
  1654. X
  1655. X/* A simple routine that checks the validity of the article's subject value.
  1656. X** A -1 means that it is NULL, otherwise it should be an offset into the
  1657. X** subject array we just unpacked.
  1658. X*/
  1659. SUBJECT *
  1660. valid_subject(num, art_num)
  1661. WORD num;
  1662. long art_num;
  1663. X{
  1664. X    if (num == -1) {
  1665. X    return Null(SUBJECT*);
  1666. X    }
  1667. X    if (num < 0 || num >= total.subject) {
  1668. X    log_error("invalid subject in thread file: %d [%ld]\n", num, art_num);
  1669. X    invalid_data = TRUE;
  1670. X    return Null(SUBJECT*);
  1671. X    }
  1672. X    return subject_array[num];
  1673. X}
  1674. X
  1675. X/* Ditto for author checking. */
  1676. AUTHOR *
  1677. valid_author(num, art_num)
  1678. WORD num;
  1679. long art_num;
  1680. X{
  1681. X    if (num == -1) {
  1682. X    return Null(AUTHOR*);
  1683. X    }
  1684. X    if (num < 0 || num >= total.author) {
  1685. X    log_error("invalid author in thread file: %d [%ld]\n", num, art_num);
  1686. X    invalid_data = TRUE;
  1687. X    return Null(AUTHOR*);
  1688. X    }
  1689. X    return author_array[num];
  1690. X}
  1691. X
  1692. X/* Our parent/sibling information is a relative offset in the article array.
  1693. X** zero for none.  Child values are always found in the very next array
  1694. X** element if child_cnt is non-zero.
  1695. X*/
  1696. ARTICLE *
  1697. valid_node(relative_offset, num)
  1698. WORD relative_offset;
  1699. int num;
  1700. X{
  1701. X    if (!relative_offset) {
  1702. X    return Nullart;
  1703. X    }
  1704. X    num += relative_offset;
  1705. X    if (num < 0 || num >= total.article) {
  1706. X    log_error("invalid node offset in thread file.\n");
  1707. X    invalid_data = TRUE;
  1708. X    return Nullart;
  1709. X    }
  1710. X    return article_array[num];
  1711. X}
  1712. X
  1713. X/* Read the articles into their linked lists.  Point everything everywhere. */
  1714. int
  1715. read_articles()
  1716. X{
  1717. X    register int count;
  1718. X    register ARTICLE *article, **article_ptr;
  1719. X    int ret;
  1720. X
  1721. X    /* Build an array to interpret interlinkages of articles. */
  1722. X    article_array = (ARTICLE**)safemalloc(total.article * sizeof (ARTICLE*));
  1723. X    article_ptr = article_array;
  1724. X
  1725. X    /* Allocate all the structures up-front so that we can point to unread
  1726. X    ** siblings as we go.
  1727. X    */
  1728. X    for (count = total.article; count--;) {
  1729. X    *article_ptr++ = (ARTICLE*)safemalloc(sizeof (ARTICLE));
  1730. X    }
  1731. X    invalid_data = FALSE;
  1732. X    article_ptr = article_array;
  1733. X    for (count = 0; count < total.article; count++) {
  1734. X    ret = fread((char*)&p_article, 1, sizeof (PACKED_ARTICLE), fp_in);
  1735. X    if (ret != sizeof (PACKED_ARTICLE)) {
  1736. X        log_error("failed article read -- %d bytes instead of %d.\n", ret, sizeof (PACKED_ARTICLE));
  1737. X        return 0;
  1738. X    }
  1739. X#ifdef TMPTHREAD
  1740. X    lp_bmap(&p_article.num, 2);
  1741. X    wp_bmap(&p_article.subject, 8);
  1742. X#endif
  1743. X
  1744. X    article = *article_ptr++;
  1745. X    article->num = p_article.num;
  1746. X    article->date = p_article.date;
  1747. X    article->subject = valid_subject(p_article.subject, p_article.num);
  1748. X    article->author = valid_author(p_article.author, p_article.num);
  1749. X    article->flags = p_article.flags;
  1750. X    article->child_cnt = p_article.child_cnt;
  1751. X    article->parent = valid_node(p_article.parent, count);
  1752. X    article->children = valid_node(article->child_cnt ? 1 : 0, count);
  1753. X    article->siblings = valid_node(p_article.siblings, count);
  1754. X    if (p_article.root < 0 || p_article.root >= total.root) {
  1755. X        log_error("invalid root offset in thread file.\n");
  1756. X        return 0;
  1757. X    }
  1758. X    article->root = root_array[p_article.root];
  1759. X    if (invalid_data) {
  1760. X        /* (Error already logged.) */
  1761. X        return 0;
  1762. X    }
  1763. X    }
  1764. X
  1765. X    /* We're done with most of the pointer arrays. */
  1766. X    safefree(&root_array);
  1767. X    safefree(&subject_array);
  1768. X
  1769. X    return 1;
  1770. X}
  1771. X
  1772. X/* Read the message-id strings and attach them to each article.  The data
  1773. X** format consists of the mushed-together null-terminated strings (a domain
  1774. X** name followed by all its unique-id prefixes) and then the article offsets
  1775. X** to which they belong.  The first domain name was omitted, as it is the
  1776. X** ".unknown." domain for those truly weird message-id's without '@'s.
  1777. X*/
  1778. int
  1779. read_ids()
  1780. X{
  1781. X    register DOMAIN *domain, *last;
  1782. X    register ARTICLE *article;
  1783. X    register char *string_ptr;
  1784. X    register int i, count;
  1785. X
  1786. X    if (!read_item(&strings, total.string2)
  1787. X     || !read_item(&ids,
  1788. X        (MEM_SIZE)(total.article+total.domain+1) * sizeof (WORD))) {
  1789. X    return 0;
  1790. X    }
  1791. X#ifdef TMPTHREAD
  1792. X    wp_bmap(ids, total.article + total.domain + 1);
  1793. X#endif
  1794. X
  1795. X    string_ptr = strings;
  1796. X    string_end = string_ptr + total.string2;
  1797. X
  1798. X    if (string_end[-1] != '\0') {
  1799. X    log_error("second string table is invalid.\n");
  1800. X    return 0;
  1801. X    }
  1802. X
  1803. X    last = &unk_domain;
  1804. X    for (i = 0, count = total.domain + 1; count--; i++) {
  1805. X    if (i) {
  1806. X        if (string_ptr >= string_end) {
  1807. X        log_error("error unpacking domain strings.\n");
  1808. X          free_partial:
  1809. X        last->link = Null(DOMAIN*);
  1810. X        article = unk_domain.ids;
  1811. X        while (article) {
  1812. X            safefree(article->id);
  1813. X            article = article->id_link;
  1814. X        }
  1815. X        domain = unk_domain.link;
  1816. X        while (domain) {
  1817. X            free(domain->name);
  1818. X            article = domain->ids;
  1819. X            while (article) {
  1820. X            safefree(article->id);
  1821. X            article = article->id_link;
  1822. X            }
  1823. X            last = domain;
  1824. X            domain = domain->link;
  1825. X            free(last);
  1826. X        }
  1827. X        return 0;
  1828. X        }
  1829. X        domain = (DOMAIN*)safemalloc(sizeof (DOMAIN));
  1830. X        give_string_to(domain->name);
  1831. X        last->link = domain;
  1832. X    } else {
  1833. X        domain = &unk_domain;
  1834. X    }
  1835. X    if (ids[i] == -1) {
  1836. X        domain->ids = Nullart;
  1837. X    } else {
  1838. X        if (ids[i] < 0 || ids[i] >= total.article) {
  1839. X          id_error:
  1840. X        log_error("error in id array.\n");
  1841. X        domain->ids = Nullart;
  1842. X        goto free_partial;
  1843. X        }
  1844. X        article = article_array[ids[i]];
  1845. X        domain->ids = article;
  1846. X        for (;;) {
  1847. X        if (string_ptr >= string_end) {
  1848. X            log_error("error unpacking domain strings.\n");
  1849. X            article->id = Nullch;
  1850. X            article->id_link = Nullart;
  1851. X            goto free_partial;
  1852. X        }
  1853. X        give_string_to(article->id);
  1854. X        article->domain = domain;
  1855. X        if (++i >= total.article + total.domain + !count) {
  1856. X            log_error("overran id array unpacking domains.\n");
  1857. X            article->id_link = Nullart;
  1858. X            goto free_partial;
  1859. X        }
  1860. X        if (ids[i] != -1) {
  1861. X            if (ids[i] < 0 || ids[i] >= total.article) {
  1862. X            goto id_error;
  1863. X            }
  1864. X            article = article->id_link = article_array[ids[i]];
  1865. X        } else {
  1866. X            article->id_link = Nullart;
  1867. X            break;
  1868. X        }
  1869. X        }
  1870. X    }
  1871. X    last = domain;
  1872. X    }
  1873. X    last->link = Null(DOMAIN*);
  1874. X    safefree(&ids);
  1875. X    safefree(&strings);
  1876. X
  1877. X    return 1;
  1878. X}
  1879. X
  1880. X/* And finally, point all the roots at their root articles and get rid
  1881. X** of anything left over that was used to aid our unpacking.
  1882. X*/
  1883. void
  1884. tweak_roots()
  1885. X{
  1886. X    register ROOT *root;
  1887. X
  1888. X    for (root = root_root; root; root = root->link) {
  1889. X    root->articles = article_array[root->seq];
  1890. X    }
  1891. X    safefree(&author_array);
  1892. X    safefree(&article_array);
  1893. X}
  1894. X
  1895. X/* A shorthand for reading a chunk of the file into a malloc'ed array.
  1896. X*/
  1897. int
  1898. read_item(dest, len)
  1899. char **dest;
  1900. MEM_SIZE len;
  1901. X{
  1902. X    int ret;
  1903. X
  1904. X    *dest = safemalloc(len);
  1905. X    ret = fread(*dest, 1, (int)len, fp_in);
  1906. X    if (ret != len) {
  1907. X    log_error("only read %ld bytes instead of %ld.\n",
  1908. X        (long)ret, (long)len);
  1909. X    free(*dest);
  1910. X    *dest = Nullch;
  1911. X    return 0;
  1912. X    }
  1913. X    return 1;
  1914. X}
  1915. END_OF_FILE
  1916. if test 15542 -ne `wc -c <'mt-read.c'`; then
  1917.     echo shar: \"'mt-read.c'\" unpacked with wrong size!
  1918. fi
  1919. # end of 'mt-read.c'
  1920. fi
  1921. if test -f 'rn.c' -a "${1}" != "-c" ; then 
  1922.   echo shar: Will not clobber existing file \"'rn.c'\"
  1923. else
  1924. echo shar: Extracting \"'rn.c'\" \(15991 characters\)
  1925. sed "s/^X//" >'rn.c' <<'END_OF_FILE'
  1926. X/*  rn -- new readnews program
  1927. X *
  1928. X *  Original Author: lwall@sdcrdcf.UUCP (Larry Wall)
  1929. X *  Organization: System Development Corporation, Santa Monica
  1930. X *  Current Author/Maintainer: sob@bcm.tmc.edu (Stan Barber)
  1931. X *  Organization: Baylor College of Medicine, Houston,Tx
  1932. X *
  1933. X *  begun:   01/14/83
  1934. X *    1.0: 04/08/83
  1935. X *      2.0: 09/01/83
  1936. X *      RRN/RN: 11/01/89
  1937. X *      4.4  07/04/91
  1938. X */
  1939. X/* This software is Copyright 1991 by Stan Barber. 
  1940. X *
  1941. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  1942. X * use this software as long as: there is no monetary profit gained
  1943. X * specifically from the use or reproduction of this software, it is not
  1944. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  1945. X * included prominently in any copy made. 
  1946. X *
  1947. X * The author make no claims as to the fitness or correctness of this software
  1948. X * for any use whatsoever, and it is provided as is. Any use of this software
  1949. X * is at the user's own risk. 
  1950. X */
  1951. X
  1952. static char rnid[] = "@(#)$Id: rn.c,v 4.4.3.1 1991/11/22 04:12:14 davison Trn $";
  1953. static char patchlevel[] = "Trn 2.1 based on rn 4.4 pl 2";
  1954. X
  1955. X/* $Log: rn.c,v $
  1956. X * Revision 4.4.2.1  1991/12/01  18:05:42  sob
  1957. X * Patchlevel 2 changes
  1958. X *
  1959. X * Revision 4.4.1.1  1991/09/25  19:38:08  sob
  1960. X * Updated patchlevel message
  1961. X *
  1962. X * Revision 4.4  1991/09/09  20:27:37  sob
  1963. X * release 4.4
  1964. X *
  1965. X *
  1966. X *
  1967. X * 
  1968. X */
  1969. X
  1970. X#include "INTERN.h"
  1971. X#include "common.h"
  1972. X#include "rn.h"
  1973. X#ifdef SERVER
  1974. X#include "server.h"
  1975. X#endif
  1976. X#include "EXTERN.h"
  1977. X#include "rcstuff.h"
  1978. X#include "term.h"
  1979. X#include "final.h"
  1980. X#include "search.h"
  1981. X#include "ngdata.h"
  1982. X#include "util.h"
  1983. X#include "only.h"
  1984. X#include "ngsrch.h"
  1985. X#include "help.h"
  1986. X#include "last.h"
  1987. X#include "init.h"
  1988. X#include "intrp.h"
  1989. X#include "rcln.h"
  1990. X#include "sw.h"
  1991. X#include "addng.h"
  1992. X#include "ng.h"
  1993. X
  1994. void
  1995. rn_init()
  1996. X{
  1997. X    ;
  1998. X}
  1999. X
  2000. void
  2001. main(argc,argv)
  2002. int argc;
  2003. char *argv[];
  2004. X{
  2005. X    bool foundany;
  2006. X    register char *s;
  2007. X    bool oh_for_the_good_old_days = FALSE;
  2008. X    int direction = 1;
  2009. X
  2010. X#if defined(USETHREADS) && !THREAD_INIT
  2011. X    /* Default to threaded operation if our name starts with a 't' */
  2012. X    if ((s = rindex(argv[0],'/')) == Nullch)
  2013. X    s = argv[0];
  2014. X    else
  2015. X    s++;
  2016. X    if (*s == 't')
  2017. X    use_threads = TRUE;
  2018. X#endif
  2019. X    foundany = initialize(argc,argv);
  2020. X
  2021. X    if (maxngtodo)
  2022. X    starthere = 0;
  2023. X    else if (!foundany) {        /* nothing to do? */
  2024. X#ifdef VERBOSE
  2025. X    if (verbose)
  2026. X        fputs("\
  2027. No unread news in subscribed-to newsgroups.  To subscribe to a new\n\
  2028. newsgroup use the g<newsgroup> command.\n\
  2029. X",stdout) FLUSH;
  2030. X#endif
  2031. X    starthere = nextrcline;
  2032. X    }
  2033. X
  2034. X    /* loop through all unread news */
  2035. X
  2036. X    {
  2037. X    bool special = FALSE;        /* temporarily allow newsgroup */
  2038. X                    /*   with no unread news? */
  2039. X    bool retry;            /* cycle back to top of list? */
  2040. X    NG_NUM recent_ng = 0;
  2041. X    
  2042. X    current_ng = 0;
  2043. X    do {
  2044. X        retry = FALSE;
  2045. X        if (findlast) {
  2046. X        findlast = FALSE;
  2047. X        starthere = 0;
  2048. X        if (*lastngname) {
  2049. X            if ((ng = find_ng(lastngname)) == nextrcline)
  2050. X            ng = 0;
  2051. X            else {
  2052. X            set_ngname(lastngname);
  2053. X                set_toread(ng);
  2054. X            if (toread[ng] <= TR_NONE)
  2055. X                ng = 0;
  2056. X            }
  2057. X        }
  2058. X        }
  2059. X        else {
  2060. X        ng = starthere;
  2061. X        starthere = 0;
  2062. X        }
  2063. X        while (ng <= nextrcline) {    /* for each newsgroup */
  2064. X        mode = 'n';
  2065. X        if (ng >= nextrcline) {    /* after the last newsgroup? */
  2066. X            ng = nextrcline;    /* force it to 1 after */
  2067. X#ifdef ONLY
  2068. X            if (maxngtodo) {
  2069. X            if (retry)
  2070. X#ifdef VERBOSE
  2071. X                IF(verbose)
  2072. X                printf("\nRestriction %s%s still in effect.\n",
  2073. X                    ngtodo[0],
  2074. X                    maxngtodo > 1 ? ", etc." : nullstr) FLUSH;
  2075. X                ELSE
  2076. X#endif
  2077. X#ifdef TERSE
  2078. X                fputs("\n(\"Only\" mode.)\n",stdout) FLUSH;
  2079. X#endif
  2080. X            else {
  2081. X#ifdef VERBOSE
  2082. X                IF(verbose)
  2083. X                fputs("\nNo articles under restriction.",
  2084. X                  stdout) FLUSH;
  2085. X                ELSE
  2086. X#endif
  2087. X#ifdef TERSE
  2088. X                fputs("\nNo \"only\" articles.",stdout) FLUSH;
  2089. X#endif
  2090. X                end_only();    /* release the restriction */
  2091. X                retry = TRUE;
  2092. X            }
  2093. X            }
  2094. X#endif
  2095. X        }
  2096. X        else {
  2097. X            bool shoe_fits;    /* newsgroup matches restriction? */
  2098. X
  2099. X            if (toread[ng] >= TR_NONE) {    /* recalc toread? */
  2100. X            set_ngname(rcline[ng]);
  2101. X            shoe_fits = inlist(ngname);
  2102. X            if (shoe_fits)
  2103. X                set_toread(ng);
  2104. X            if (paranoid) {
  2105. X                recent_ng = current_ng;
  2106. X                current_ng = ng;
  2107. X                cleanup_rc();
  2108. X                    /* this may move newsgroups around */
  2109. X                ng = current_ng;
  2110. X                set_ngname(rcline[ng]);
  2111. X            }
  2112. X            }
  2113. X            if (toread[ng] < (maxngtodo||special ? TR_NONE : TR_ONE)
  2114. X             || !shoe_fits) {        /* unwanted newsgroup? */
  2115. X            ng += direction;    /* then skip it */
  2116. X            if (ng < 0) {
  2117. X               ng = 1;
  2118. X               direction = 1;
  2119. X            }
  2120. X            continue;
  2121. X            }
  2122. X        }
  2123. X        special = FALSE;    /* go back to normal mode */
  2124. X        if (ng != current_ng) {
  2125. X            recent_ng = current_ng;
  2126. X                    /* remember previous newsgroup */
  2127. X            current_ng = ng;    /* remember current newsgroup */
  2128. X        }
  2129. X    reask_newsgroup:
  2130. X        unflush_output();    /* disable any ^O in effect */
  2131. X        if (ng >= nextrcline) {
  2132. X            dfltcmd = (retry ? "npq" : "qnp");
  2133. X#ifdef VERBOSE
  2134. X            IF(verbose)
  2135. X            printf("\n******** End of newsgroups--what next? [%s] ",
  2136. X                dfltcmd);
  2137. X            ELSE
  2138. X#endif
  2139. X#ifdef TERSE
  2140. X            printf("\n**** End--next? [%s] ", dfltcmd);
  2141. X#endif
  2142. X        } else {
  2143. X#ifdef USETHREADS
  2144. X            ThreadedGroup = (use_threads
  2145. X            && (thread_always || rcchar[ng] == '0'));
  2146. X            dfltcmd = (use_threads && select_on
  2147. X            && (ART_NUM)toread[ng] >= select_on ? "+ynq" : "ynq");
  2148. X#else
  2149. X            dfltcmd = "ynq";
  2150. X#endif
  2151. X#ifdef VERBOSE
  2152. X            IF(verbose)
  2153. X            printf("\n******** %3ld unread article%s in %s--read now? [%s] ",
  2154. X                (long)toread[ng], (toread[ng]==TR_ONE ? nullstr : "s"),
  2155. X                ngname, dfltcmd);
  2156. X            ELSE
  2157. X#endif
  2158. X#ifdef TERSE
  2159. X            printf("\n**** %3ld in %s--read? [%s] ",
  2160. X                (long)toread[ng],
  2161. X                ngname,dfltcmd);
  2162. X#endif
  2163. X        }
  2164. X        fflush(stdout);
  2165. X    reinp_newsgroup:
  2166. X        eat_typeahead();
  2167. X        getcmd(buf);
  2168. X        if (errno || *buf == '\f') {
  2169. X            putchar('\n') FLUSH; /* if return from stop signal */
  2170. X            goto reask_newsgroup;    /* give them a prompt again */
  2171. X        }
  2172. X        setdef(buf,dfltcmd);
  2173. X#ifdef VERIFY
  2174. X        printcmd();
  2175. X#endif
  2176. X    do_command:
  2177. X        direction = 1;        /* default to forward motion */
  2178. X        switch (*buf) {
  2179. X        case 'P':        /* goto previous newsgroup */
  2180. X            special = TRUE;    /* don't skip it if toread==0 */
  2181. X            /* FALL THROUGH */
  2182. X        case 'p':        /* find previous unread newsgroup */
  2183. X            if (ng > 0)
  2184. X            ng--;
  2185. X            direction = -1;    /* go backward in the newsrc */
  2186. X            break;
  2187. X        case '-':
  2188. X            ng = recent_ng;    /* recall previous newsgroup */
  2189. X            if (ng < nextrcline)
  2190. X            if (!get_ng(rcline[ng],FALSE))
  2191. X                ng = current_ng;
  2192. X            special = TRUE;    /* don't skip it if toread==0 */
  2193. X            break;
  2194. X        case 'q': case 'Q': case 'x':    /* quit? */
  2195. X            oh_for_the_good_old_days = (*buf == 'x');
  2196. X            putchar('\n') FLUSH;
  2197. X            ng = nextrcline+1;    /* satisfy */
  2198. X            retry = FALSE;    /*   loop conditions */
  2199. X            break;
  2200. X        case '^':
  2201. X            putchar('\n') FLUSH;
  2202. X            ng = 0;
  2203. X            break;
  2204. X        case 'n':        /* find next unread newsgroup */
  2205. X            if (ng == nextrcline) {
  2206. X            putchar('\n') FLUSH;
  2207. X            retry = TRUE;
  2208. X            }
  2209. X            else if (toread[ng] > TR_NONE)
  2210. X            retry = TRUE;
  2211. X            ng++;
  2212. X            break;
  2213. X        case 'N':        /* goto next newsgroup */
  2214. X            special = TRUE;    /* and don't skip it if toread==0 */
  2215. X            ng++;
  2216. X            break;
  2217. X        case '1':        /* goto 1st newsgroup */
  2218. X            ng = 0;
  2219. X            special = TRUE;    /* and don't skip it if toread==0 */
  2220. X            break;
  2221. X        case '$':
  2222. X            ng = nextrcline;    /* goto last newsgroup */
  2223. X            retry = TRUE;
  2224. X            break;
  2225. X        case 'L':
  2226. X            list_newsgroups();
  2227. X            goto reask_newsgroup;
  2228. X        case '/': case '?':    /* scan for newsgroup pattern */
  2229. X#ifdef NGSEARCH
  2230. X            switch (ng_search(buf,TRUE)) {
  2231. X            case NGS_ERROR:
  2232. X            goto reask_newsgroup;
  2233. X            case NGS_ABORT:
  2234. X            goto reinp_newsgroup;
  2235. X            case NGS_INTR:
  2236. X#ifdef VERBOSE
  2237. X            IF(verbose)
  2238. X                fputs("\n(Interrupted)\n",stdout) FLUSH;
  2239. X            ELSE
  2240. X#endif
  2241. X#ifdef TERSE
  2242. X                fputs("\n(Intr)\n",stdout) FLUSH;
  2243. X#endif
  2244. X            ng = current_ng;
  2245. X            goto reask_newsgroup;
  2246. X            case NGS_FOUND:
  2247. X            special = TRUE;    /* don't skip it if toread==0 */
  2248. X            break;
  2249. X            case NGS_NOTFOUND:
  2250. X#ifdef VERBOSE
  2251. X            IF(verbose)
  2252. X                fputs("\n\nNot found--use a or g to add newsgroups\n",
  2253. X                stdout) FLUSH;
  2254. X            ELSE
  2255. X#endif
  2256. X#ifdef TERSE
  2257. X                fputs("\n\nNot found\n",stdout) FLUSH;
  2258. X#endif
  2259. X            goto reask_newsgroup;
  2260. X            }
  2261. X#else
  2262. X            notincl("/");
  2263. X#endif
  2264. X            break;
  2265. X        case 'm':
  2266. X#ifndef RELOCATE
  2267. X            notincl("m");
  2268. X            break;
  2269. X#endif            
  2270. X        case 'g':    /* goto named newsgroup */
  2271. X            if (!finish_command(FALSE))
  2272. X                    /* if they didn't finish command */
  2273. X            goto reinp_newsgroup;    /* go try something else */
  2274. X            for (s = buf+1; *s == ' '; s++);
  2275. X                    /* skip leading spaces */
  2276. X#ifdef RELOCATE
  2277. X            if (!*s && *buf == 'm' && ngname && ng < nextrcline)
  2278. X            strcpy(s,ngname);
  2279. X#endif
  2280. X            if (isalpha(*s)) 
  2281. X            set_ngname(s);
  2282. X            else {
  2283. X            if (isdigit(*s)) {
  2284. X                int rcnum;
  2285. X                rcnum = atoi(s);
  2286. X                if (rcnum < nextrcline)
  2287. X                set_ngname(rcline[rcnum]);
  2288. X                else {
  2289. X                printf("\nOnly %d groups. Try again.\n",
  2290. X                    nextrcline) FLUSH;
  2291. X                goto reask_newsgroup;
  2292. X                }
  2293. X            }
  2294. X            else {
  2295. X                printf("\nPlease specify a newsgroup.\n") FLUSH;
  2296. X                goto reask_newsgroup;
  2297. X            }
  2298. X            }
  2299. X#ifdef RELOCATE
  2300. X            if (!get_ng(ngname,*buf=='m'))
  2301. X                        /* try to find newsgroup */
  2302. X#else
  2303. X            if (!get_ng(ngname,FALSE))    /* try to find newsgroup */
  2304. X#endif
  2305. X            ng = current_ng;/* if not found, go nowhere */
  2306. X            special = TRUE;    /* don't skip it if toread==0 */
  2307. X            break;
  2308. X#ifdef DEBUGGING
  2309. X        case 'D':
  2310. X            printf("\nTries: %d Hits: %d\n",
  2311. X            softtries,softtries-softmisses) FLUSH;
  2312. X            goto reask_newsgroup;
  2313. X#endif
  2314. X        case '!':        /* shell escape */
  2315. X            if (escapade())     /* do command */
  2316. X            goto reinp_newsgroup;
  2317. X                    /* if rubbed out, re input */
  2318. X            goto reask_newsgroup;
  2319. X        case Ctl('k'):        /* edit global KILL file */
  2320. X            edit_kfile();
  2321. X            goto reask_newsgroup;
  2322. X        case 'c':        /* catch up */
  2323. X#ifdef CATCHUP
  2324. reask_catchup:
  2325. X#ifdef VERBOSE
  2326. X            IF(verbose)
  2327. X            in_char("\nDo you really want to mark everything as read? [yn] ", 'C');
  2328. X            ELSE
  2329. X#endif
  2330. X#ifdef TERSE
  2331. X            in_char("\nReally? [ynh] ", 'C');
  2332. X#endif
  2333. X            setdef(buf,"y");
  2334. X#ifdef VERIFY
  2335. X            printcmd();
  2336. X#endif
  2337. X            putchar('\n') FLUSH;
  2338. X            if (*buf == 'h') {
  2339. X#ifdef VERBOSE
  2340. X            printf("Type y or SP to mark all articles as read.\n");
  2341. X            printf("Type n to leave articles marked as they are.\n");
  2342. X#else
  2343. X            printf("y or SP to mark all read.\n");
  2344. X            printf("n to forget it.\n");
  2345. X#endif
  2346. X            goto reask_catchup;
  2347. X            }
  2348. X            else if (*buf != 'y' && *buf != 'n' && *buf != 'q') {
  2349. X            printf(hforhelp);
  2350. X            settle_down();
  2351. X            goto reask_catchup;
  2352. X            } else if (*buf == 'y' && ng<nextrcline)
  2353. X            catch_up(ng);
  2354. X            else
  2355. X            retry = TRUE;
  2356. X            ng++;
  2357. X#else
  2358. X            notincl("c");
  2359. X#endif
  2360. X            break;
  2361. X#ifdef USETHREADS
  2362. X        case 't':
  2363. X            if (!use_threads)
  2364. X            printf("\n\nNot running in thread mode.\n");
  2365. X            else if (ng < nextrcline && toread[ng] >= TR_NONE) {
  2366. X            bool force_threaded = (rcchar[ng] == ':');
  2367. X            rcchar[ng] = (force_threaded ? '0' : ':');
  2368. X            printf("\n\n%s will %s.\n", rcline[ng],
  2369. X                force_threaded ? "always be read threaded"
  2370. X                : "be read unthreaded if no thread file exists"
  2371. X                ) FLUSH;
  2372. X            set_toread(ng);
  2373. X            }
  2374. X            special = TRUE;    /* don't skip it if toread==0 */
  2375. X            break;
  2376. X#endif
  2377. X        case 'u':        /* unsubscribe */
  2378. X            if (ng < nextrcline && toread[ng] >= TR_NONE) {
  2379. X                    /* unsubscribable? */
  2380. X            printf(unsubto,rcline[ng]) FLUSH;
  2381. X            rcchar[ng] = NEGCHAR;
  2382. X                    /* unsubscribe to (from?) it */
  2383. X            toread[ng] = TR_UNSUB;
  2384. X                    /* and make line invisible */
  2385. X            ng++;        /* do an automatic 'n' */
  2386. X            }
  2387. X            break;
  2388. X        case 'h': {        /* help */
  2389. X            int cmd;
  2390. X
  2391. X            if ((cmd = help_ng()) > 0)
  2392. X            pushchar(cmd);
  2393. X            goto reask_newsgroup;
  2394. X        }
  2395. X        case 'A':
  2396. X            if (ng >= nextrcline)
  2397. X            break;
  2398. reask_abandon:
  2399. X#ifdef VERBOSE
  2400. X            IF(verbose)
  2401. X            in_char("\nAbandon changes to current newsgroup? [yn] ", 'B');
  2402. X            ELSE
  2403. X#endif
  2404. X#ifdef TERSE
  2405. X            in_char("\nAbandon? [ynh] ", 'B');
  2406. X#endif
  2407. X            setdef(buf,"y");
  2408. X#ifdef VERIFY
  2409. X            printcmd();
  2410. X#endif
  2411. X            putchar('\n') FLUSH;
  2412. X            if (*buf == 'h') {
  2413. X#ifdef VERBOSE
  2414. X            printf("Type y or SP to abandon the changes to this group since you started trn.\n");
  2415. X            printf("Type n to leave the group as it is.\n");
  2416. X#else
  2417. X            printf("y or SP to abandon changes to this group.\n");
  2418. X            printf("n to forget it.\n");
  2419. X#endif
  2420. X            goto reask_abandon;
  2421. X            }
  2422. X            else if (*buf != 'y' && *buf != 'n' && *buf != 'q') {
  2423. X            printf(hforhelp);
  2424. X            settle_down();
  2425. X            goto reask_abandon;
  2426. X            } else if (*buf == 'y')
  2427. X            abandon_ng(ng);
  2428. X            special = TRUE;    /* don't skip it if toread==0 */
  2429. X            break;
  2430. X        case 'a':
  2431. X#ifndef FINDNEWNG
  2432. X            notincl("a");
  2433. X            goto reask_newsgroup;
  2434. X#else
  2435. X            /* FALL THROUGH */
  2436. X#endif
  2437. X        case 'o':
  2438. X#ifdef ONLY
  2439. X        {
  2440. X#ifdef FINDNEWNG
  2441. X            bool doscan = (*buf == 'a');
  2442. X#endif
  2443. X
  2444. X            if (!finish_command(TRUE)) /* get rest of command */
  2445. X            goto reinp_newsgroup;    /* if rubbed out, try something else */
  2446. X            end_only();
  2447. X            if (buf[1]) {
  2448. X            bool minusd = instr(buf+1,"-d", TRUE) != Nullch;
  2449. X
  2450. X            sw_list(buf+1);
  2451. X            if (minusd)
  2452. X                cwd_check();
  2453. X            putchar('\n') FLUSH;
  2454. X#ifdef FINDNEWNG
  2455. X            if (doscan && maxngtodo)
  2456. X                scanactive();
  2457. X#endif
  2458. X            }
  2459. X            ng = 0;        /* simulate ^ */
  2460. X            retry = FALSE;
  2461. X            break;
  2462. X        }
  2463. X#else
  2464. X            notincl("o");
  2465. X            goto reask_newsgroup;
  2466. X#endif
  2467. X        case '&':
  2468. X            if (switcheroo()) /* get rest of command */
  2469. X            goto reinp_newsgroup;    /* if rubbed out, try something else */
  2470. X            goto reask_newsgroup;
  2471. X        case 'l': {        /* list other newsgroups */
  2472. X            if (!finish_command(TRUE)) /* get rest of command */
  2473. X            goto reinp_newsgroup;    /* if rubbed out, try something else */
  2474. X            for (s = buf+1; *s == ' '; s++);
  2475. X                        /* skip leading spaces */
  2476. X            sprintf(cmd_buf,"%s '%s'",filexp(NEWSGROUPS),s);
  2477. X            resetty();
  2478. X            if (doshell(sh,cmd_buf))
  2479. X#ifdef VERBOSE
  2480. X            IF(verbose)
  2481. X                fputs("    (Error from newsgroups program)\n",
  2482. X                stdout) FLUSH;
  2483. X            ELSE
  2484. X#endif
  2485. X#ifdef TERSE
  2486. X                fputs("(Error)\n",stdout) FLUSH;
  2487. X#endif
  2488. X            noecho();
  2489. X            crmode();
  2490. X            goto reask_newsgroup;
  2491. X        }
  2492. X#ifdef USETHREADS
  2493. X        case 'U': case '+':
  2494. X#endif
  2495. X        case '.': case '=':
  2496. X        case 'y': case 'Y': case '\t': /* do normal thing */
  2497. X            if (ng >= nextrcline) {
  2498. X            fputs("\nNot on a newsgroup.",stdout) FLUSH;
  2499. X            goto reask_newsgroup;
  2500. X            }
  2501. X#ifdef USETHREADS
  2502. X            else if (*buf == '+' || *buf == 'U' || *buf == '=') {
  2503. X            buf[1] = '\0';
  2504. X            s = savestr(buf);
  2505. X            }
  2506. X#else
  2507. X            if (*buf == '=')
  2508. X            s = savestr("=");
  2509. X#endif
  2510. X            else if (*buf == '.') {    /* start command? */
  2511. X            if (!finish_command(FALSE)) /* get rest of command */
  2512. X                goto reinp_newsgroup;
  2513. X            s = savestr(buf+1);
  2514. X                    /* do_newsgroup will free it */
  2515. X            }
  2516. X            else
  2517. X            s = Nullch;
  2518. X            if (toread[ng])
  2519. X            retry = TRUE;
  2520. X            switch (do_newsgroup(s)) {
  2521. X            case NG_ERROR:
  2522. X            case NG_NORM:
  2523. X            ng++;
  2524. X            break;
  2525. X            case NG_ASK:
  2526. X            goto reask_newsgroup;
  2527. X            case NG_SELPRIOR:
  2528. X            *buf = 'p';
  2529. X            goto do_command;
  2530. X            case NG_SELNEXT:
  2531. X            *buf = 'n';
  2532. X            goto do_command;
  2533. X            case NG_MINUS:
  2534. X            ng = recent_ng;    /* recall previous newsgroup */
  2535. X            special = TRUE;    /* don't skip it if toread==0 */
  2536. X            break;
  2537. X            }
  2538. X            break;
  2539. X#ifdef STRICTCR
  2540. X        case '\n':
  2541. X            fputs(badcr,stdout) FLUSH;
  2542. X            goto reask_newsgroup;
  2543. X#endif
  2544. X        case 'v':
  2545. X            printf("\n%s",rnid);
  2546. X            printf("\n%s",patchlevel);
  2547. X            printf("\nSend bugs to davison@borland.com\n") FLUSH;
  2548. X            goto reask_newsgroup;
  2549. X        default:
  2550. X            printf("\n%s",hforhelp) FLUSH;
  2551. X            settle_down();
  2552. X            goto reask_newsgroup;
  2553. X        }
  2554. X        }
  2555. X    } while (retry);
  2556. X    }
  2557. X
  2558. X    /* now write .newsrc back out */
  2559. X
  2560. X    write_rc();
  2561. X
  2562. X    if (oh_for_the_good_old_days)
  2563. X    get_old_rc();
  2564. X
  2565. X    finalize(0);            /* and exit */
  2566. X}
  2567. X
  2568. X/* set current newsgroup */
  2569. X
  2570. void
  2571. set_ngname(what)
  2572. char *what;
  2573. X{
  2574. X    int len = strlen(what)+1;
  2575. X
  2576. X    growstr(&ngname,&ngnlen,len);
  2577. X    strcpy(ngname,what);
  2578. X    growstr(&ngdir,&ngdlen,len);
  2579. X    strcpy(ngdir,getngdir(ngname));
  2580. X}
  2581. X
  2582. static char *myngdir;
  2583. static int ngdirlen = 0;
  2584. X
  2585. char *
  2586. getngdir(ngnam)
  2587. char *ngnam;
  2588. X{
  2589. X    register char *s;
  2590. X
  2591. X    growstr(&myngdir,&ngdirlen,strlen(ngnam)+1);
  2592. X    strcpy(myngdir,ngnam);
  2593. X    for (s = myngdir; *s; s++)
  2594. X    if (*s == '.')
  2595. X        *s = '/';
  2596. X    return myngdir;
  2597. X}
  2598. END_OF_FILE
  2599. if test 15991 -ne `wc -c <'rn.c'`; then
  2600.     echo shar: \"'rn.c'\" unpacked with wrong size!
  2601. fi
  2602. # end of 'rn.c'
  2603. fi
  2604. if test -f 'util.c' -a "${1}" != "-c" ; then 
  2605.   echo shar: Will not clobber existing file \"'util.c'\"
  2606. else
  2607. echo shar: Extracting \"'util.c'\" \(14626 characters\)
  2608. sed "s/^X//" >'util.c' <<'END_OF_FILE'
  2609. X/* $Id: util.c,v 4.4 1991/09/09 20:27:37 sob Exp sob $
  2610. X *
  2611. X * $Log: util.c,v $
  2612. X * Revision 4.4  1991/09/09  20:27:37  sob
  2613. X * release 4.4
  2614. X *
  2615. X *
  2616. X * 
  2617. X */
  2618. X/* This software is Copyright 1991 by Stan Barber. 
  2619. X *
  2620. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  2621. X * use this software as long as: there is no monetary profit gained
  2622. X * specifically from the use or reproduction of this software, it is not
  2623. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  2624. X * included prominently in any copy made. 
  2625. X *
  2626. X * The author make no claims as to the fitness or correctness of this software
  2627. X * for any use whatsoever, and it is provided as is. Any use of this software
  2628. X * is at the user's own risk. 
  2629. X */
  2630. X
  2631. X#include "EXTERN.h"
  2632. X#include "common.h"
  2633. X#include "final.h"
  2634. X#include "INTERN.h"
  2635. X#include "util.h"
  2636. X
  2637. X#ifdef TZSET
  2638. X#include <time.h>
  2639. X#else
  2640. X#include <sys/time.h>
  2641. X#include <sys/timeb.h>
  2642. X#endif
  2643. X
  2644. void
  2645. util_init()
  2646. X{
  2647. X    ;
  2648. X}
  2649. X    
  2650. X/* fork and exec a shell command */
  2651. X
  2652. int
  2653. doshell(shl,s)
  2654. char *s, *shl;
  2655. X{
  2656. X    int status, pid, w;
  2657. X    char *shell;
  2658. X
  2659. X#ifdef SIGTSTP
  2660. X    sigset(SIGTSTP,SIG_DFL);
  2661. X    sigset(SIGTTOU,SIG_DFL);
  2662. X    sigset(SIGTTIN,SIG_DFL);
  2663. X#endif
  2664. X    if (shl != Nullch)
  2665. X    shell = shl;
  2666. X    else if ((shell = getenv("SHELL")) == Nullch || !*shell)
  2667. X    shell = PREFSHELL;
  2668. X    if ((pid = vfork()) == 0) {
  2669. X#ifdef SERVER
  2670. X        int i;
  2671. X
  2672. X    /* This is necessary to keep bourne shell from puking */
  2673. X
  2674. X        for (i = 3; i < 10; ++i)
  2675. X                close(i);
  2676. X#endif /* SERVER */
  2677. X
  2678. X    if (*s)
  2679. X        execl(shell, shell, "-c", s, Nullch);
  2680. X    else
  2681. X        execl(shell, shell, Nullch, Nullch, Nullch);
  2682. X    _exit(127);
  2683. X    }
  2684. X    signal(SIGINT, SIG_IGN);
  2685. X#ifdef SIGQUIT
  2686. X    signal(SIGQUIT, SIG_IGN);
  2687. X#endif 
  2688. X    waiting = TRUE;
  2689. X    while ((w = wait(&status)) != pid)
  2690. X    if (w == -1 && errno != EINTR)
  2691. X        break;
  2692. X    if (w == -1)
  2693. X    status = -1;
  2694. X    waiting = FALSE;
  2695. X    sigset(SIGINT, int_catcher);    /* always catch interrupts */
  2696. X#ifdef SIGQUIT
  2697. X    signal(SIGQUIT, SIG_DFL);
  2698. X#endif 
  2699. X#ifdef SIGTSTP
  2700. X    sigset(SIGTSTP,stop_catcher);
  2701. X    sigset(SIGTTOU,stop_catcher);
  2702. X    sigset(SIGTTIN,stop_catcher);
  2703. X#endif
  2704. X    return status;
  2705. X}
  2706. X
  2707. static char nomem[] = "rn: out of memory!\n";
  2708. X
  2709. X/* paranoid version of malloc */
  2710. X
  2711. char *
  2712. safemalloc(size)
  2713. MEM_SIZE size;
  2714. X{
  2715. X    char *ptr;
  2716. X    char *malloc();
  2717. X
  2718. X    ptr = malloc(size ? size : (MEM_SIZE)1);
  2719. X    if (ptr == Nullch) {
  2720. X    fputs(nomem,stdout) FLUSH;
  2721. X    sig_catcher(0);
  2722. X    }
  2723. X    return ptr;
  2724. X}
  2725. X
  2726. X/* paranoid version of realloc */
  2727. X
  2728. char *
  2729. saferealloc(where,size)
  2730. char *where;
  2731. MEM_SIZE size;
  2732. X{
  2733. X    char *ptr;
  2734. X    char *realloc();
  2735. X
  2736. X    ptr = realloc(where,size?size:1);    /* realloc(0) is NASTY on our system */
  2737. X    if (ptr == Nullch) {
  2738. X    fputs(nomem,stdout) FLUSH;
  2739. X    sig_catcher(0);
  2740. X    }
  2741. X    return ptr;
  2742. X}
  2743. X
  2744. X/* safe version of string copy */
  2745. X
  2746. char *
  2747. safecpy(to,from,len)
  2748. char *to;
  2749. register char *from;
  2750. register int len;
  2751. X{
  2752. X    register char *dest = to;
  2753. X
  2754. X    if (from != Nullch) 
  2755. X    for (len--; len && (*dest++ = *from++); len--) ;
  2756. X    *dest = '\0';
  2757. X    return to;
  2758. X}
  2759. X
  2760. X/* safe version of string concatenate, with \n deletion and space padding */
  2761. X
  2762. char *
  2763. safecat(to,from,len)
  2764. char *to;
  2765. register char *from;
  2766. register int len;
  2767. X{
  2768. X    register char *dest = to;
  2769. X
  2770. X    len--;                /* leave room for null */
  2771. X    if (*dest) {
  2772. X    while (len && *dest++) len--;
  2773. X    if (len) {
  2774. X        len--;
  2775. X        *(dest-1) = ' ';
  2776. X    }
  2777. X    }
  2778. X    if (from != Nullch)
  2779. X    while (len && (*dest++ = *from++)) len--;
  2780. X    if (len)
  2781. X    dest--;
  2782. X    if (*(dest-1) == '\n')
  2783. X    dest--;
  2784. X    *dest = '\0';
  2785. X    return to;
  2786. X}
  2787. X
  2788. X/* copy a string up to some (non-backslashed) delimiter, if any */
  2789. X
  2790. char *
  2791. cpytill(to,from,delim)
  2792. register char *to, *from;
  2793. register int delim;
  2794. X{
  2795. X    for (; *from; from++,to++) {
  2796. X    if (*from == '\\' && from[1] == delim)
  2797. X        from++;
  2798. X    else if (*from == delim)
  2799. X        break;
  2800. X    *to = *from;
  2801. X    }
  2802. X    *to = '\0';
  2803. X    return from;
  2804. X}
  2805. X
  2806. X/* return ptr to little string in big string, NULL if not found */
  2807. X
  2808. char *
  2809. instr(big, little, case_matters)
  2810. char *big, *little;
  2811. int case_matters;
  2812. X{
  2813. X    register char *t, *s, *x;
  2814. X
  2815. X    for (t = big; *t; t++) {
  2816. X    for (x=t,s=little; *s; x++,s++) {
  2817. X        if (!*x)
  2818. X        return Nullch;
  2819. X        if (case_matters == TRUE) {
  2820. X        if(*s != *x)
  2821. X            break;
  2822. X        } else {
  2823. X        register char c,d;
  2824. X        if (isupper(*s)) 
  2825. X            c = tolower(*s);
  2826. X        else
  2827. X            c = *s;
  2828. X        if (isupper(*x)) 
  2829. X            d = tolower(*x);
  2830. X        else
  2831. X            d = *x;
  2832. X        if ( c != d )
  2833. X            break;
  2834. X       }
  2835. X    }
  2836. X    if (!*s)
  2837. X        return t;
  2838. X    }
  2839. X    return Nullch;
  2840. X}
  2841. X
  2842. X/* effective access */
  2843. X
  2844. X#ifdef SETUIDGID
  2845. int
  2846. eaccess(filename, mod)
  2847. char *filename;
  2848. int mod;
  2849. X{
  2850. X    int protection, euid;
  2851. X    
  2852. X    mod &= 7;                /* remove extraneous garbage */
  2853. X    if (stat(filename, &filestat) < 0)
  2854. X    return -1;
  2855. X    euid = geteuid();
  2856. X    if (euid == ROOTID)
  2857. X    return 0;
  2858. X    protection = 7 & (filestat.st_mode >>
  2859. X      (filestat.st_uid == euid ? 6 :
  2860. X        (filestat.st_gid == getegid() ? 3 : 0)
  2861. X      ));
  2862. X    if ((mod & protection) == mod)
  2863. X    return 0;
  2864. X    errno = EACCES;
  2865. X    return -1;
  2866. X}
  2867. X#endif
  2868. X
  2869. X/*
  2870. X * Get working directory
  2871. X */
  2872. X#ifndef GETWD
  2873. X#ifdef GETCWD
  2874. char *
  2875. getwd(np)
  2876. char *np;
  2877. X{
  2878. X    char * name;
  2879. X    extern char * getcwd();
  2880. X    name = getcwd(np,512);
  2881. X    return(name);
  2882. X}
  2883. X#else
  2884. char *
  2885. getwd(np)            /* shorter but slower */
  2886. char *np;
  2887. X{
  2888. X    FILE *popen();
  2889. X    FILE *pipefp = popen("/bin/pwd","r");
  2890. X
  2891. X    if (pipefp == Nullfp) {
  2892. X    printf("Can't run /bin/pwd\n") FLUSH;
  2893. X    finalize(1);
  2894. X    }
  2895. X    fgets(np,512,pipefp);
  2896. X    np[strlen(np)-1] = '\0';    /* wipe out newline */
  2897. X    pclose(pipefp);
  2898. X    return np;
  2899. X}
  2900. X#endif
  2901. X#endif
  2902. X/* just like fgets but will make bigger buffer as necessary */
  2903. X
  2904. char *
  2905. get_a_line(original_buffer,buffer_length,fp)
  2906. char *original_buffer;
  2907. register int buffer_length;
  2908. XFILE *fp;
  2909. X{
  2910. X    register int bufix = 0;
  2911. X    register int nextch;
  2912. X    register char *some_buffer_or_other = original_buffer;
  2913. X
  2914. X    do {
  2915. X    if (bufix >= buffer_length) {
  2916. X        buffer_length *= 2;
  2917. X        if (some_buffer_or_other == original_buffer) {
  2918. X                    /* currently static? */
  2919. X        some_buffer_or_other = safemalloc((MEM_SIZE)buffer_length+1);
  2920. X        strncpy(some_buffer_or_other,original_buffer,buffer_length/2);
  2921. X                    /* so we must copy it */
  2922. X        }
  2923. X        else {            /* just grow in place, if possible */
  2924. X        some_buffer_or_other = saferealloc(some_buffer_or_other,
  2925. X            (MEM_SIZE)buffer_length+1);
  2926. X        }
  2927. X    }
  2928. X    if ((nextch = getc(fp)) == EOF)
  2929. X        return Nullch;
  2930. X    some_buffer_or_other[bufix++] = (char) nextch;
  2931. X    } while (nextch && nextch != '\n');
  2932. X    some_buffer_or_other[bufix] = '\0';
  2933. X    len_last_line_got = bufix;
  2934. X    return some_buffer_or_other;
  2935. X}
  2936. X
  2937. X/* copy a string to a safe spot */
  2938. X
  2939. char *
  2940. savestr(str)
  2941. char *str;
  2942. X{
  2943. X    register char *newaddr = safemalloc((MEM_SIZE)(strlen(str)+1));
  2944. X
  2945. X    strcpy(newaddr,str);
  2946. X    return newaddr;
  2947. X}
  2948. X
  2949. int
  2950. makedir(dirname,nametype)
  2951. register char *dirname;
  2952. int nametype;
  2953. X{
  2954. X#ifdef MAKEDIR
  2955. X    register char *end;
  2956. X    register char *s;
  2957. X    char tmpbuf[1024];
  2958. X    register char *tbptr = tmpbuf+5;
  2959. X
  2960. X    for (end = dirname; *end; end++) ;    /* find the end */
  2961. X    if (nametype == MD_FILE) {        /* not to create last component? */
  2962. X    for (--end; end != dirname && *end != '/'; --end) ;
  2963. X    if (*end != '/')
  2964. X        return 0;            /* nothing to make */
  2965. X    *end = '\0';            /* isolate file name */
  2966. X    }
  2967. X    strcpy(tmpbuf,"mkdir");
  2968. X
  2969. X    s = end;
  2970. X    for (;;) {
  2971. X    if (stat(dirname,&filestat) >= 0 && (filestat.st_mode & S_IFDIR)) {
  2972. X                    /* does this much exist as a dir? */
  2973. X        *s = '/';            /* mark this as existing */
  2974. X        break;
  2975. X    }
  2976. X    s = rindex(dirname,'/');    /* shorten name */
  2977. X    if (!s)                /* relative path! */
  2978. X        break;            /* hope they know what they are doing */
  2979. X    *s = '\0';            /* mark as not existing */
  2980. X    }
  2981. X    
  2982. X    for (s=dirname; s <= end; s++) {    /* this is grody but efficient */
  2983. X    if (!*s) {            /* something to make? */
  2984. X        sprintf(tbptr," %s",dirname);
  2985. X        tbptr += strlen(tbptr);    /* make it, sort of */
  2986. X        *s = '/';            /* mark it made */
  2987. X    }
  2988. X    }
  2989. X    if (nametype == MD_DIR)        /* don't need final slash unless */
  2990. X    *end = '\0';            /*  a filename follows the dir name */
  2991. X
  2992. X    return (tbptr==tmpbuf+5 ? 0 : doshell(sh,tmpbuf));
  2993. X                    /* exercise our faith */
  2994. X#else
  2995. X    sprintf(cmd_buf,"%s %s %d", filexp(DIRMAKER), dirname, nametype);
  2996. X    return doshell(sh,cmd_buf);
  2997. X#endif
  2998. X}
  2999. X
  3000. X#ifdef SETENV
  3001. static bool firstsetenv = TRUE;
  3002. extern char **environ;
  3003. X
  3004. void
  3005. setenv(nam,val)
  3006. char *nam, *val;
  3007. X{
  3008. X    register int i=envix(nam);        /* where does it go? */
  3009. X
  3010. X    if (!environ[i]) {            /* does not exist yet */
  3011. X    if (firstsetenv) {        /* need we copy environment? */
  3012. X        int j;
  3013. X#ifndef lint
  3014. X        char **tmpenv = (char**)    /* point our wand at memory */
  3015. X        safemalloc((MEM_SIZE) (i+2) * sizeof(char*));
  3016. X#else
  3017. X        char **tmpenv = Null(char **);
  3018. X#endif /* lint */
  3019. X    
  3020. X        firstsetenv = FALSE;
  3021. X        for (j=0; j<i; j++)        /* copy environment */
  3022. X        tmpenv[j] = environ[j];
  3023. X        environ = tmpenv;        /* tell exec where it is now */
  3024. X    }
  3025. X#ifndef lint
  3026. X    else
  3027. X        environ = (char**) saferealloc((char*) environ,
  3028. X        (MEM_SIZE) (i+2) * sizeof(char*));
  3029. X                    /* just expand it a bit */
  3030. X#endif /* lint */
  3031. X    environ[i+1] = Nullch;    /* make sure it's null terminated */
  3032. X    }
  3033. X    environ[i] = safemalloc((MEM_SIZE) strlen(nam) + strlen(val) + 2);
  3034. X                    /* this may or may not be in */
  3035. X                    /* the old environ structure */
  3036. X    sprintf(environ[i],"%s=%s",nam,val);/* all that work just for this */
  3037. X}
  3038. X
  3039. int
  3040. envix(nam)
  3041. char *nam;
  3042. X{
  3043. X    register int i, len = strlen(nam);
  3044. X
  3045. X    for (i = 0; environ[i]; i++) {
  3046. X    if (strnEQ(environ[i],nam,len) && environ[i][len] == '=')
  3047. X        break;            /* strnEQ must come first to avoid */
  3048. X    }                    /* potential SEGV's */
  3049. X    return i;
  3050. X}
  3051. X#endif
  3052. X
  3053. void
  3054. notincl(feature)
  3055. char *feature;
  3056. X{
  3057. X    printf("\nNo room for feature \"%s\" on this machine.\n",feature) FLUSH;
  3058. X}
  3059. X
  3060. char *
  3061. getval(nam,def)
  3062. char *nam,*def;
  3063. X{
  3064. X    char *val;
  3065. X
  3066. X    if ((val = getenv(nam)) == Nullch || !*val)
  3067. X    val = def;
  3068. X    return val;
  3069. X}
  3070. X
  3071. X/* grow a static string to at least a certain length */
  3072. X
  3073. void
  3074. growstr(strptr,curlen,newlen)
  3075. char **strptr;
  3076. int *curlen;
  3077. int newlen;
  3078. X{
  3079. X    if (newlen > *curlen) {        /* need more room? */
  3080. X    if (*curlen)
  3081. X        *strptr = saferealloc(*strptr,(MEM_SIZE)newlen);
  3082. X    else
  3083. X        *strptr = safemalloc((MEM_SIZE)newlen);
  3084. X    *curlen = newlen;
  3085. X    }
  3086. X}
  3087. X
  3088. void
  3089. setdef(buffer,dflt)
  3090. char *buffer,*dflt;
  3091. X{
  3092. X#ifdef STRICTCR
  3093. X    if (*buffer == ' ')
  3094. X#else
  3095. X    if (*buffer == ' ' || *buffer == '\n')
  3096. X#endif
  3097. X    {
  3098. X    if (*dflt == '^' && isupper(dflt[1]))
  3099. X        *buffer = Ctl(dflt[1]);
  3100. X    else
  3101. X        *buffer = *dflt;
  3102. X    }
  3103. X}
  3104. X
  3105. X#ifdef SERVER
  3106. int nntp_get(buf, len)
  3107. char *buf;
  3108. int  len;
  3109. X{
  3110. X     int n;
  3111. X#ifdef HAVESIGHOLD
  3112. X     sighold(SIGINT);
  3113. X#endif
  3114. X     n = get_server(buf, len);
  3115. X#ifdef HAVESIGHOLD
  3116. X     sigrelse(SIGINT);
  3117. X#endif
  3118. X     return n;
  3119. X}
  3120. X#endif
  3121. X
  3122. X#ifndef STRFTIME
  3123. X/*
  3124. X * strftime: print formatted information about a given time.
  3125. X * Adapted from the routine by Eric R. Smith, Michal Jaegermann,
  3126. X * Arnold Robins, and Paul Close.
  3127. X */
  3128. X
  3129. X/* Configuration choices for %x and %X */
  3130. X
  3131. X#undef LOCAL_DDMMYY    /* choose DD/MM/YY instead of MM/DD/YY */
  3132. X#undef LOCAL_DOTTIME    /* choose HH.MM.SS instead of HH:MM:SS */
  3133. X
  3134. static char *mth_name[] = {
  3135. X    "January", "February", "March", "April", "May", "June",
  3136. X    "July", "August", "September", "October", "November", "December"
  3137. X};
  3138. X
  3139. static char *day_name[] = {
  3140. X    "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
  3141. X    "Saturday"
  3142. X};
  3143. X
  3144. X#ifdef TZSET
  3145. extern char *tzname[];
  3146. X#endif
  3147. X
  3148. int
  3149. strftime(str, maxsize, fmt, ts)
  3150. char *str;
  3151. int maxsize;
  3152. char *fmt;
  3153. struct tm *ts;
  3154. X{
  3155. X    int num = 0, len;
  3156. X    char ch;
  3157. X    char *putstr, *s;
  3158. X    char tmpbuf[80];
  3159. X
  3160. X    if (maxsize-- <= 0)
  3161. X    return 0;
  3162. X
  3163. X    for (;;) {
  3164. X    if (!(ch = *fmt++))
  3165. X        break;
  3166. X    if (num == maxsize) {
  3167. X        num = 0;
  3168. X        break;
  3169. X    }
  3170. X    if (ch != '%') {
  3171. X        *str++ = ch;
  3172. X        num++;
  3173. X        continue;
  3174. X    }
  3175. X    /* assume the finished product will be sprintf'ed into tmpbuf */
  3176. X    putstr = tmpbuf;
  3177. X
  3178. X    switch (ch = *fmt++) {
  3179. X    case 'A':
  3180. X    case 'a':
  3181. X        if (ts->tm_wday < 0 || ts->tm_wday > 6)
  3182. X        putstr = "?";
  3183. X        else
  3184. X        if (ch == 'A')
  3185. X            putstr = day_name[ts->tm_wday];
  3186. X        else
  3187. X            sprintf(tmpbuf, "%-.3s", day_name[ts->tm_wday]);
  3188. X        break;
  3189. X    case 'B':
  3190. X    case 'b':
  3191. X    case 'h':
  3192. X        if (ts->tm_mon < 0 || ts->tm_mon > 11)
  3193. X        putstr = "?";
  3194. X        else if (ch == 'B')
  3195. X        putstr = mth_name[ts->tm_mon];
  3196. X        else
  3197. X        sprintf(tmpbuf, "%-.3s", mth_name[ts->tm_mon]);
  3198. X        break;
  3199. X    case 'C':
  3200. X        strftime(tmpbuf, sizeof tmpbuf, "%A, %B %e, %Y", ts);
  3201. X        break;
  3202. X    case 'c':
  3203. X        strftime(tmpbuf, sizeof tmpbuf, "%x %X", ts);
  3204. X        break;
  3205. X    case 'D':
  3206. X#ifndef LOCAL_DDMMYY
  3207. X    case 'x':
  3208. X#endif
  3209. X        strftime(tmpbuf, sizeof tmpbuf, "%m/%d/%y", ts);
  3210. X        break;
  3211. X    case 'd':
  3212. X        sprintf(tmpbuf, "%02d", ts->tm_mday);
  3213. X        break;
  3214. X    case 'e':    /* day of month, blank padded */
  3215. X        sprintf(tmpbuf, "%2d", ts->tm_mday);
  3216. X        break;
  3217. X    case 'H':
  3218. X        sprintf(tmpbuf, "%02d", ts->tm_hour);
  3219. X        break;
  3220. X    case 'I':
  3221. X    {
  3222. X        int n;
  3223. X
  3224. X        n = ts->tm_hour;
  3225. X        if (n == 0)
  3226. X        n = 12;
  3227. X        else if (n > 12)
  3228. X        n -= 12;
  3229. X        sprintf(tmpbuf, "%02d", n);
  3230. X        break;
  3231. X    }
  3232. X    case 'j':
  3233. X        sprintf(tmpbuf, "%03d", ts->tm_yday + 1);
  3234. X        break;
  3235. X    case 'm':
  3236. X        sprintf(tmpbuf, "%02d", ts->tm_mon + 1);
  3237. X        break;
  3238. X    case 'M':
  3239. X        sprintf(tmpbuf, "%02d", ts->tm_min);
  3240. X        break;
  3241. X    case 'p':
  3242. X        putstr = (ts->tm_hour < 12) ? "AM" : "PM";
  3243. X        break;
  3244. X    case 'r':
  3245. X        strftime(tmpbuf, sizeof tmpbuf, "%I:%M:%S %p", ts);
  3246. X        break;
  3247. X    case 'R':
  3248. X        strftime(tmpbuf, sizeof tmpbuf, "%H:%M", ts);
  3249. X        break;
  3250. X    case 'S':
  3251. X        sprintf(tmpbuf, "%02d", ts->tm_sec);
  3252. X        break;
  3253. X    case 'T':
  3254. X#ifndef LOCAL_DOTTIME
  3255. X    case 'X':
  3256. X#endif
  3257. X        strftime(tmpbuf, sizeof tmpbuf, "%H:%M:%S", ts);
  3258. X        break;
  3259. X    case 'U':    /* week of year - starting Sunday */
  3260. X        sprintf(tmpbuf, "%02d", (ts->tm_yday - ts->tm_wday + 10) / 7);
  3261. X        break;
  3262. X    case 'W':    /* week of year - starting Monday */
  3263. X        sprintf(tmpbuf, "%02d", (ts->tm_yday - ((ts->tm_wday + 6) % 7)
  3264. X            + 10) / 7);
  3265. X        break;
  3266. X    case 'w':
  3267. X        sprintf(tmpbuf, "%d", ts->tm_wday);
  3268. X        break;
  3269. X    case 'y':
  3270. X        sprintf(tmpbuf, "%02d", ts->tm_year % 100);
  3271. X        break;
  3272. X#ifdef LOCAL_DOTTIME
  3273. X    case 'X':
  3274. X        strftime(tmpbuf, sizeof tmpbuf, "%H.%M.%S", ts);
  3275. X        break;
  3276. X#endif
  3277. X#ifdef LOCAL_DDMMYY
  3278. X    case 'x':
  3279. X        strftime(tmpbuf, sizeof tmpbuf, "%d/%m/%y", ts);
  3280. X        break;
  3281. X#endif
  3282. X    case 'Y':
  3283. X        sprintf(tmpbuf, "%d", ts->tm_year + 1900);
  3284. X        break;
  3285. X    case 'Z':
  3286. X#ifdef TZSET
  3287. X        sprintf(tmpbuf, "%s", tzname[ts->tm_isdst]);
  3288. X#else
  3289. X        sprintf(tmpbuf, "%s", ts->tm_zone);
  3290. X#endif
  3291. X        break;
  3292. X    case '%':
  3293. X    case '\0':
  3294. X        putstr = "%";
  3295. X        break;
  3296. X    case 'n':    /* same as \n */
  3297. X        putstr = "\n";
  3298. X        break;
  3299. X    case 't':    /* same as \t */
  3300. X        putstr = "\n";
  3301. X        break;
  3302. X    default:
  3303. X        sprintf(tmpbuf, "%%%c", ch);
  3304. X        break;
  3305. X    }
  3306. X    len = strlen(putstr);
  3307. X    num += len;
  3308. X    if (num > maxsize) {
  3309. X        len -= num - maxsize;
  3310. X        num = 0;
  3311. X        ch = '\0';
  3312. X    }
  3313. X    strncpy(str, putstr, len);
  3314. X    str += len;
  3315. X    if (!ch)
  3316. X        break;
  3317. X    }
  3318. X    *str = '\0';
  3319. X    return num;
  3320. X}
  3321. X#endif /* no STRFTIME */
  3322. END_OF_FILE
  3323. if test 14626 -ne `wc -c <'util.c'`; then
  3324.     echo shar: \"'util.c'\" unpacked with wrong size!
  3325. fi
  3326. # end of 'util.c'
  3327. fi
  3328. echo shar: End of archive 6 \(of 13\).
  3329. cp /dev/null ark6isdone
  3330. MISSING=""
  3331. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
  3332.     if test ! -f ark${I}isdone ; then
  3333.     MISSING="${MISSING} ${I}"
  3334.     fi
  3335. done
  3336. if test "${MISSING}" = "" ; then
  3337.     echo You have unpacked all 13 archives.
  3338.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  3339. else
  3340.     echo You still need to unpack the following archives:
  3341.     echo "        " ${MISSING}
  3342. fi
  3343. ##  End of shell archive.
  3344. exit 0
  3345.